Linq-to-entities - метод Include() не загружается
Если я использую объединение, метод Include() больше не работает, например:
from e in dc.Entities.Include("Properties")
join i in dc.Items on e.ID equals i.Member.ID
where (i.Collection.ID == collectionID)
select e
e.Properties
не загружен
Без объединения функция Include() работает
Ли
Ответы
Ответ 1
UPDATE: На самом деле я недавно добавил еще один Совет, который охватывает это, и предоставляет альтернативное, вероятно, лучшее решение. Идея состоит в том, чтобы отложить использование Include() до конца запроса, см. Это для получения дополнительной информации: Совет 22 - Как включить include включить include
Известное ограничение в Entity Framework при использовании Include().
Некоторые операции просто не поддерживаются с помощью Include.
Похоже, вы столкнулись с одним из этих ограничений, чтобы обойти это, вы должны попробовать что-то вроде этого:
var results =
from e in dc.Entities //Notice no include
join i in dc.Items on e.ID equals i.Member.ID
where (i.Collection.ID == collectionID)
select new {Entity = e, Properties = e.Properties};
Это приведет к возврату свойств, и если отношения между объектом и свойствами будут от одного до многих (но не многие из многих), вы обнаружите, что каждый получившийся анонимный тип имеет те же значения:
anonType.Entity.Properties
anonType.Properties
Это побочный эффект функции в платформе Entity Framework, называемой фиксацией отношений.
Смотрите Совет 1 в моей серии советов EF для получения дополнительной информации.
Ответ 2
Попробуйте следующее:
var query = (ObjectQuery<Entities>)(from e in dc.Entities
join i in dc.Items on e.ID equals i.Member.ID
where (i.Collection.ID == collectionID)
select e)
return query.Include("Properties")
Ответ 3
Итак, каково имя свойства навигации в "Entity", которое относится к "Item.Member" (т.е. является другим концом навигации). Вы должны использовать это вместо соединения. Например, если "entity" добавляет свойство "Member" с мощностью 1, а член имеет свойство "Элементы с мощностью многих", вы можете сделать это:
from e in dc.Entities.Include("Properties")
where e.Member.Items.Any(i => i.Collection.ID == collectionID)
select e
Я догадываюсь о свойствах вашей модели здесь, но это должно дать вам общую идею. В большинстве случаев использование соединения в LINQ to Entities неверно, поскольку оно предполагает, что либо ваши навигационные свойства не настроены правильно, либо вы не используете их.
Ответ 4
Итак, я понимаю, что опаздываю на вечеринку здесь, однако я думал, что добавлю свои выводы. Это действительно должен быть комментарий к сообщению Alex James, но поскольку у меня нет репутации, он должен будет пойти здесь.
Итак, мой ответ: он, похоже, не работает вообще, как вы бы хотели. Алекс Джеймс дает два интересных решения, однако, если вы попробуете их и проверите SQL, это ужасно.
В качестве примера я работал:
var theRelease = from release in context.Releases
where release.Name == "Hello World"
select release;
var allProductionVersions = from prodVer in context.ProductionVersions
where prodVer.Status == 1
select prodVer;
var combined = (from release in theRelease
join p in allProductionVersions on release.Id equals p.ReleaseID
select release).Include(release => release.ProductionVersions);
var allProductionsForChosenRelease = combined.ToList();
Это следует за более простым из двух примеров. Без включения он создает совершенно респектабельный sql:
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Name] AS [Name]
FROM [dbo].[Releases] AS [Extent1]
INNER JOIN [dbo].[ProductionVersions] AS [Extent2] ON [Extent1].[Id] = [Extent2].[ReleaseID]
WHERE ('Hello World' = [Extent1].[Name]) AND (1 = [Extent2].[Status])
Но с, OMG:
SELECT
[Project1].[Id1] AS [Id],
[Project1].[Id] AS [Id1],
[Project1].[Name] AS [Name],
[Project1].[C1] AS [C1],
[Project1].[Id2] AS [Id2],
[Project1].[Status] AS [Status],
[Project1].[ReleaseID] AS [ReleaseID]
FROM ( SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Name] AS [Name],
[Extent2].[Id] AS [Id1],
[Extent3].[Id] AS [Id2],
[Extent3].[Status] AS [Status],
[Extent3].[ReleaseID] AS [ReleaseID],
CASE WHEN ([Extent3].[Id] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1]
FROM [dbo].[Releases] AS [Extent1]
INNER JOIN [dbo].[ProductionVersions] AS [Extent2] ON [Extent1].[Id] = [Extent2].[ReleaseID]
LEFT OUTER JOIN [dbo].[ProductionVersions] AS [Extent3] ON [Extent1].[Id] = [Extent3].[ReleaseID]
WHERE ('Hello World' = [Extent1].[Name]) AND (1 = [Extent2].[Status])
) AS [Project1]
ORDER BY [Project1].[Id1] ASC, [Project1].[Id] ASC, [Project1].[C1] ASC
Общий мусор. Ключевым моментом здесь является тот факт, что он возвращает внешнюю объединенную версию таблицы, которая не была ограничена статусом = 1.
Это приводит к возврату возвращаемых данных WRONG:
Id Id1 Name C1 Id2 Status ReleaseID
2 1 Hello World 1 1 2 1
2 1 Hello World 1 2 1 1
Обратите внимание, что статус 2 возвращается туда, несмотря на наше ограничение. Это просто не работает.
Если я где-то ошибаюсь, я был бы рад узнать, так как это насмехается над Линком. Мне нравится эта идея, но исполнение в настоящее время не представляется возможным.
Из любопытства я попытался использовать dbml LinqToSQL, а не LinqToEntities edmx, создавший беспорядок выше:
SELECT [t0].[Id], [t0].[Name], [t2].[Id] AS [Id2], [t2].[Status], [t2].[ReleaseID], (
SELECT COUNT(*)
FROM [dbo].[ProductionVersions] AS [t3]
WHERE [t3].[ReleaseID] = [t0].[Id]
) AS [value]
FROM [dbo].[Releases] AS [t0]
INNER JOIN [dbo].[ProductionVersions] AS [t1] ON [t0].[Id] = [t1].[ReleaseID]
LEFT OUTER JOIN [dbo].[ProductionVersions] AS [t2] ON [t2].[ReleaseID] = [t0].[Id]
WHERE ([t0].[Name] = @p0) AND ([t1].[Status] = @p1)
ORDER BY [t0].[Id], [t1].[Id], [t2].[Id]
Немного более компактный - странный аргумент count, но общий общий FAIL.
Кто-нибудь действительно использовал этот материал в реальном бизнес-приложении? Я действительно начинаю удивляться...
Пожалуйста, скажите мне, что я пропустил что-то очевидное, так как мне очень нравится Linq!
Ответ 5
Попробуйте более подробный способ сделать более или менее ту же самую вещь, чтобы получить те же результаты, но с большим количеством datacalls:
var mydata = from e in dc.Entities
join i in dc.Items
on e.ID equals i.Member.ID
where (i.Collection.ID == collectionID)
select e;
foreach (Entity ent in mydata) {
if(!ent.Properties.IsLoaded) { ent.Properties.Load(); }
}
Вы все еще получаете тот же (неожиданный) результат?
EDIT. Изменено первое предложение, так как оно было неправильным. Спасибо за комментарий указателя!