У меня есть два linq (к EF4) запросы, которые возвращают различные результаты. Первый запрос содержит корректные результаты, но не форматируется/проектируется право.
второй запрос - то, что я хочу только он пропускающий некоторые данные.
сопроводительный текст http://img220.imageshack.us/img220/9678/schema.png
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
. Но этот результат проекции является неправильным...
Хорошо..далее...
var yyy = (from cp in _connectedClientRepository
.GetConnectedClients(new[] { "LogEntry", "LogEntry.GameFile" })
.AsExpandable()
.Where(predicate)
select cp.LogEntry)
.ToList();
Примечание: изображение выше имеет опечатку в нем..., обратите внимание, что введенный код включать ассоциаций является правильным (т.е. 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;
}
}
Похоже, вам нужен еще один метод репозитория, который сделает это за вас; _connectedClientsRepository.GetLogEntriesOfConnectedClients ()
.
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».
Я подозреваю, что предложение Крейга Стунца может сработать, но если это не так, то следующее должно сработать:
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