Linq-to-entity - метод Include () не загружается - PullRequest
46 голосов
/ 27 апреля 2009

Если я использую объединение, метод 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 ()

Lee

Ответы [ 5 ]

54 голосов
/ 06 мая 2009

ОБНОВЛЕНИЕ: На самом деле я недавно добавил еще один совет, который охватывает это, и предоставляет альтернативное, вероятно, лучшее решение. Идея состоит в том, чтобы отложить использование Include () до конца запроса, см. Это для получения дополнительной информации: Совет 22 - Как включить 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 Tips для получения дополнительной информации.

20 голосов
/ 19 апреля 2010

Попробуйте это:

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") 
4 голосов
/ 28 апреля 2009

Так, как называется свойство навигации в «Entity», которое относится к «Item.Member» (то есть является другим концом навигации). Вы должны использовать это вместо соединения. Например, если «сущность» добавляет свойство с именем Member с количеством элементов, равным 1, и элемент имеет свойство с именем Items, имеющее множество элементов, вы можете сделать это:

from e in dc.Entities.Include("Properties")
where e.Member.Items.Any(i => i.Collection.ID == collectionID) 
select e

Я угадываю свойства вашей модели здесь, но это должно дать вам общее представление. В большинстве случаев использование объединения в LINQ to Entities некорректно , так как предполагает, что либо ваши навигационные свойства настроены неправильно, либо вы их не используете.

1 голос
/ 02 октября 2014

Итак, я понимаю, что опаздываю на вечеринку здесь, однако я решил добавить свои выводы. Это действительно должен быть комментарий к сообщению Алекса Джеймса, но, поскольку у меня нет репутации, мне придется пойти сюда.

Итак, мой ответ: кажется, что он не работает совсем так, как вы хотели бы. Алекс Джеймс предлагает два интересных решения, однако, если вы попробуете их и проверите 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.

В результате возвращаются НЕПРАВИЛЬНЫЕ данные:

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, а не edmx LinqToEntities, который привел беспорядок выше:

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]

Чуть более компактно - странное количество, но в целом тот же FAIL.

Кто-нибудь когда-либо использовал этот материал в реальном бизнес-приложении? Я действительно начинаю задумываться ... Пожалуйста, скажите мне, что я упустил что-то очевидное, потому что я действительно хочу любить Линка!

0 голосов
/ 27 апреля 2009

Попробуйте более подробный способ сделать более или менее то же самое получить те же результаты, но с большим количеством вызовов данных:

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(); }
}

Вы все еще получаете тот же (неожиданный) результат?

РЕДАКТИРОВАТЬ : изменено первое предложение, так как оно было неверным. Спасибо за комментарий-указатель!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...