在Entity Framework 4.1中查询实体的子集合

rem*_*y97 3 .net linq-to-entities entity-framework-4.1

我有一组实体,我在DbContext中从IDbSet查询过.我现在想迭代每个实体并查询它们的子集合,这些集合在实体中定义为ICollection.在子集合上调用AsQueryable()并对其运行我的linq查询是否正确?如果是这样,我的查询是linq-to-objects还是由EF实现的集合对象实现了进入数据库的IQueryable?

感谢您对此有任何见解.

Lad*_*nka 5

它完全取决于您的实体的定义方式以及是否启用了延迟加载.您的查询IDbSet将是linq-to-entities.如果启用了延迟加载,则访问已加载实体的每个导航属性将触发将加载所有相关实体的数据库查询.AsQueryable在这里没有任何影响你仍然会对所有加载的数据执行linq-to-objects查询.在这种情况下,使用预先加载并将相关实体与主实体一起加载是更好的方法:

var query = context.YourEntitySet.Include(e => e.YourNavProperty);
Run Code Online (Sandbox Code Playgroud)

在某些情况下,执行此查询可以在内部生成非常大的结果集.

如果你有很多相关的实体,并且你真的只想加载一些非常小的子集,你可以使用以下方法:

context.Entry(yourLoadedMainEntity)
       .Collection(e => e.YourNavProperty)
       .Query()
       .Where(...)
       .Load();
Run Code Online (Sandbox Code Playgroud)

这是强制EF仅使用linq到实体加载相关实体的子集的方法.您仍然必须为每个加载的主实体执行此操作.执行这么多查询非常慢.它仍然是N + 1问题.

另一个也是最复杂的优化是在单个查询中加载所有主要实体,在另一个查询中加载所有相关实体:

var query = context.YourEntitySet;
var relatedQuery = from e in context.YourRelatedEntitySet
                   join m in context.YourEntitySet on e.MainId equals m.Id
                   where ...
                   select e;
Run Code Online (Sandbox Code Playgroud)

一旦执行了两个查询,实体框架应确保导航属性正确填充相关实体,但这仅在延迟加载关闭但实体由上下文跟踪时才有效(我从未尝试使用DbContext API,但它使用了ObjectContext API) .