我有两个linq(到EF4)查询,返回不同的结果。第一个查询包含正确的结果,但未正确格式化/投影。
第二个查询是我想要的,但它缺少一些数据。
alt text 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();
alt text http://img231.imageshack.us/img231/6541/image2ys.png
注意属性GameFile
。它不 null。这很棒:)请注意linq查询?我急切加载一个LogEntry
,然后急切地加载GameFile
(对于每个急切加载的LogEntry)。
这就是我所追求的 - >对于急切加载的每个LogEntry
,请急切加载GameFile
。但这个预测结果是错误的......
好的..下一个......
var yyy = (from cp in _connectedClientRepository
.GetConnectedClients(new[] { "LogEntry", "LogEntry.GameFile" })
.AsExpandable()
.Where(predicate)
select cp.LogEntry)
.ToList();
alt text http://img24.imageshack.us/img24/4417/image1tu.png
注意:上面的图片中有一个拼写错误...请注意包含关联的类型代码是正确的(即。LogEntry.GameFile
),而图片上的拼写错误。
现在正确投影 - >所有LogEntries
结果。但请注意GameFile
属性现在是如何null?我不确定为什么:(我以为我正确地渴望加载正确的链。所以这是正确的投影,但结果不正确。
public IQueryable<ConnectedClient> GetConnectedClients(
string[] includeAssociations)
{
return Context.ConnectedClients
.IncludeAssociations(includeAssociations)
.AsQueryable();
}
public static class Extensions
{
public static IQueryable<T> IncludeAssociation<T>(
this IQueryable<T> source, string includeAssociation)
{
if (!string.IsNullOrEmpty(includeAssociation))
{
var objectQuery = source as ObjectQuery<T>;
if (objectQuery != null)
{
return objectQuery.Include(includeAssociation);
}
}
return source;
}
public static IQueryable<T> IncludeAssociations<T>(
this IQueryable<T> source, params string[] includeAssociations)
{
if (includeAssociations != null)
{
foreach (string association in includeAssociations)
{
source = source.IncludeAssociation(association);
}
}
return source;
}
}
答案 0 :(得分:2)
我怀疑Craig Stuntz的建议可能会有效,但如果没有,那么以下内容肯定会有效:
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
答案 1 :(得分:1)
Include()
适用于查询结果,而不是中间查询。您可以在此帖子中详细了解Include()
。因此,一种解决方案是将Include()
应用于整个查询,如下所示:
var q = ((from cp in _connectedClientRepository.GetConnectedClients()
.AsExpandable()
.Where(predicate)
select cp.LogEntry)
as ObjectQuery).Include("GameFile").ToList();
那可能工作,但它很难看。我们可以做得更好吗?
我可以想办法解决这个问题。大多数情况下,它取决于您是否确实需要返回的实体类型。我不能说如果没有看到你的其余代码就是这种情况。通常,当您要更新(或以其他方式修改)它们时,您需要返回实体类型。如果您选择显示或计算目的,返回POCO而不是实体类型通常是更好的策略。您可以使用projection执行此操作,当然它适用于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,因为您打算更新它们。在这种情况下,我会像Tomas建议的那样为LogEntries编写一个单独的存储库方法。但是如果我打算更新它们,我只会这样做,我可能会把它写成更新方法,而不是“Get”方法。
答案 2 :(得分:-1)
您似乎还需要一个存储库方法,它将为您执行此操作; _connectedClientsRepository.GetLogEntriesOfConnectedClients()
。