Кто-то может объяснить, почему эти два запроса linq возвращают различные результаты?

У меня есть два linq (к EF4) запросы, которые возвращают различные результаты. Первый запрос содержит корректные результаты, но не форматируется/проектируется право.

второй запрос - то, что я хочу только он пропускающий некоторые данные.

Схема

сопроводительный текст http://img220.imageshack.us/img220/9678/schema.png

Запрос 1

var xxxx = (from cp in _connectedClientRepository
            .GetConnectedClients(new[] { "LogEntry", "LogEntry.GameFile" })
            .AsExpandable()
            .Where(predicate)
            select cp)
    .ToList();

сопроводительный текст http://img231.imageshack.us/img231/6541/image2ys.png

Заметьте свойство GameFile . Это не является пустым. Здорово :) Заметить запрос linq? Я - нетерпеливая загрузка a LogEntry и затем нетерпеливая загрузка a GameFile (для каждого нетерпеливого загруженного LogEntry).

Это - то, что я после-> для каждого LogEntry это нетерпеливо загруженный, нетерпеливая загрузка GameFile. Но этот результат проекции является неправильным...

Хорошо..далее...

Запрос 2

var yyy = (from cp in _connectedClientRepository
            .GetConnectedClients(new[] { "LogEntry", "LogEntry.GameFile" })
            .AsExpandable()
            .Where(predicate)
        select cp.LogEntry)
    .ToList();

alt text

Примечание: изображение выше имеет опечатку в нем..., обратите внимание, что введенный код включать ассоциаций является правильным (т.е. LogEntry.GameFile) в то время как изображение имеет его typo'd.

Корректная проекция теперь-> все LogEntries результаты. Но заметьте как GameFile свойство является теперь пустым? Я не уверен почему :( Я думал i правильно нетерпеливый, загрузил корректную цепочку. Таким образом, это - корректная проекция, но с неправильными результатами.

Обязательный код Репозитория.

public IQueryable GetConnectedClients(
    string[] includeAssociations)
{
    return Context.ConnectedClients
        .IncludeAssociations(includeAssociations)
        .AsQueryable();
}

public static class Extensions
{
    public static IQueryable IncludeAssociation(
        this IQueryable source, string includeAssociation)
    {
        if (!string.IsNullOrEmpty(includeAssociation))
        {
            var objectQuery = source as ObjectQuery;

            if (objectQuery != null)
            {
                return objectQuery.Include(includeAssociation);
            }
        }

        return source;
    }

    public static IQueryable IncludeAssociations(
        this IQueryable source, params string[] includeAssociations)
    {
        if (includeAssociations != null)
        {
            foreach (string association in includeAssociations)
            {
                source = source.IncludeAssociation(association);
            }
        }

        return source;
    }
}

Обновления

  • 1: Зафиксированный некоторая опечатка в замеченном в примерах кода.
  • 2: Добавленный код репозитория для помощи любому, кто смущен.

11
задан Glorfindel 16 June 2019 в 10:06
поделиться

3 ответа

Похоже, вам нужен еще один метод репозитория, который сделает это за вас; _connectedClientsRepository.GetLogEntriesOfConnectedClients () .

-1
ответ дан 3 December 2019 в 12:17
поделиться

Include () работает с результатами запроса, а не с промежуточными запросами. Вы можете узнать больше о Include () в этом сообщении. Таким образом, одним из решений является применение Include () ко всему запросу, например:

var q = ((from cp in _connectedClientRepository.GetConnectedClients()
                                               .AsExpandable()
                                               .Where(predicate) 
          select cp.LogEntry) 
         as ObjectQuery).Include("GameFile").ToList();

Это, вероятно, сработает , но это некрасиво. Можем ли мы сделать лучше?

Я могу думать о двух способах решения этой проблемы. В основном это зависит от того, действительно ли вам нужны возвращаемые типы сущностей. Я не могу сказать, так ли это, не видя остальной части вашего кода. Как правило, вам необходимо возвращать типы сущностей, когда вы собираетесь их обновлять (или иным образом изменять). Если вы выбираете для отображения или расчетов, часто лучше возвращать POCO вместо типов сущностей. Вы можете сделать это с помощью проекции , и, конечно же, это работает в EF 1. В этом случае вы должны изменить свой метод репозитория, чтобы возвращать типы POCO:

 public IQueryable<ClientInfo> GetConnectedClients()
 {
      return from cp in _context.Clients
             where // ...
             select new ClientInfo
             {
                 Id = cp.Id,
                 ClientName = cp.ClientName,
                 LogEntry = new LogEntryInfo
                            {
                                LogEntryId = cp.LogEntry.LogEntryId,
                                GameFile = new GameFileInfo
                                           {
                                               GameFileId = cp.LogEntry.GameFile.GameFileId,
                                               // etc.
                                           },
                                // etc.
                            },
                  // etc.
             };
 }

Обратите внимание, что при использовании проекции нет желания загрузка, без отложенной загрузки и без явной загрузки. Есть только ваше намерение, выраженное в виде запроса. Поставщик LINQ определит, что вам нужно , даже если вы в дальнейшем составите запрос вне репозитория!

С другой стороны, вам может потребоваться возвращать типы сущностей вместо POCO, потому что вы собираетесь их обновить. В этом случае я бы написал отдельный метод репозитория для LogEntries, как предложил Томас. Но я бы сделал это только в том случае, если бы намеревался обновить их, и я мог бы написать это как метод обновления, а не как метод «Get».

1
ответ дан 3 December 2019 в 12:17
поделиться

Я подозреваю, что предложение Крейга Стунца может сработать, но если это не так, то следующее должно сработать:

 var xxxx =_connectedClientRepository
        .GetConnectedClients(new[] { "LogEntry", "LogEntry.GameFile" })
        .AsExpandable()
        .Where(predicate)
        .ToList() // execute query
        .Select(cp => cp.LogEntry); // use linq-to-objects to project the result
2
ответ дан 3 December 2019 в 12:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: