Подтвердить что ты не робот

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() работает

Ли

4b9b3361

Ответ 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. Изменено первое предложение, так как оно было неправильным. Спасибо за комментарий указателя!