我对EF来说还是个新手,这一直困扰着我几天:
我有一个用户实体。它有一个父WorkSpace,它有一组Users。 每个用户还在User.Schedules属性中有一组子计划。
我在这样的对象中导航:
var query = myUser.WorkSpace.Users.SelectMany(u => u.Schedules);
当枚举query
的结果时(myUser是之前使用.Find(userid)加载的User实例),我注意到EF为WorkSpace中的每个用户向数据库发出一个查询。
为什么EF不能从单个查询中获取结果,从myUser的主键开始,并将其与所涉及的所有表连接起来?
如果我直接从这样的上下文中做其他事情,它可以正常工作:
context.Users.Where(u => u.ID = userid).SelectMany(u => u.WorkSpace.Users.SelectMany(u => u.Schedules))
我做错了吗?
答案 0 :(得分:2)
我们来看第一个问题:
var query = myUser.WorkSpace.Users.SelectMany(u => u.Schedules);
如果您查看query
变量的类型,您会看到它是IEnumerable<Schedule>
,这意味着这是一个常规的LINQ to Objects查询。为什么?因为它从物化对象开始,然后加入另一个对象/集合等。这与EF延迟加载功能相结合,导致了多个数据库查询行为。
如果您对第二个查询执行相同的操作:
var query = context.Users.Where(u => u.ID = userid)
.SelectMany(u => u.WorkSpace.Users.SelectMany(u => u.Schedules))
您会注意到query
的类型现在是IQueryable<Schedule>
,这意味着您现在有了LINQ to Entities查询。这是因为查询中使用的context.Users
和其他对象/集合都不是真实对象 - 它们只是用于构建,执行和实现查询的元数据。
总结一下,你没有做错事。延迟加载以这种方式工作。如果您不关心所谓的N+1 query问题,可以使用第一种方法。如果你关心,那就用第二个。