延迟加载是否会在迭代时加载整个集合?

时间:2012-02-24 21:26:27

标签: c# linq entity-framework lazy-loading ienumerable

即使您只迭代集合中的第一个项目,延迟加载是否会加载整个集合?或者它只加载在集合中迭代的项目?

...或者我不知道我在说什么?

3 个答案:

答案 0 :(得分:5)

@Slauma的答案是正确的 - 第一次访问导航属性时会加载整个集合。它必须采用“普通”导航属性,因为该集合只是一个常规的ICollection<>而不是IQueryable<>。

但是,如果您不希望加载整个集合,则可以执行两项操作。如果您有可用的上下文,那么您可以使用Query方法真正加载懒惰。例如:

foreach (var role in context.Entry(user).Collection(e => e.Roles).Query())
{    
    Console.WriteLine(role.Name);    
    if (role.Name == "Role1")    
        break;    
}    

如果您事先知道要查找的实体,可以进一步了解这一点。例如,要加载Role1,您可以执行以下操作:

var role1 = context.Entry(user)
                .Collection(e => e.Roles)
                .Query()
                .Single(r => r.Name == "Role1");

这篇文章提供了有关Query方法的更多细节:

http://blogs.msdn.com/b/adonet/archive/2011/01/31/using-dbcontext-in-ef-feature-ctp5-part-6-loading-related-entities.aspx

如果您希望在运行查询时不需要上下文,那么请查看这些博客文章,解释如何制作超级惰性集合:

http://blog.oneunicorn.com/2011/03/28/extra-lazy-collection-count-with-ef-4-1-part-1/

以及更一般的IQueryable支持的集合:

http://blog.oneunicorn.com/2011/03/30/a-more-general-queryable-collection/

答案 1 :(得分:4)

当您开始迭代集合时,延迟加载会加载整个集合。示例:假设user 1的角色为“Role1”,“Role2”,“Role3”(user.Rolesvirtual):

var user = context.Users.Single(u => u.Id == 1);
foreach (var role in user.Roles) // DB query happens here once
{
    Console.WriteLine(role.Name);
    if (role.Name == "Role1")
        break;
}

虽然您永远不会访问Role2Role3,但它们仍然已被加载。

答案 2 :(得分:1)

每次迭代可枚举的源时,它会迭代一次投影。