考虑具有两个外键([Person]
,[Phone_Numbers]
)的表[Business_Information]
。使用EF Core时,我们只需使用Person
方法dbContext.Find
即可找到var person = await db.Context.FindAsync<Person>(1)
;但是,Find
方法仅查找跟踪缓存中的实体,并且不处理关系属性。为了解决这个问题,我们可以调用Entry
方法来附加dbContext.Entry<Person>(person).Reference(x=> x.Business_Information)
之类的属性。考虑到提供的示例,我们必须在这种情况下调用Entry
方法两次:
dbContext.Entry<Person>(person).Reference(x=> x.Business_Information).Load();
dbContext.Entry<Person>(person).Collection(x=> x.Phone_Numbers).Load();
另一种解决方案是使用Include
方法:
var person = await dbContext.Set<Person>().Include("Business_Information").Include("Phone_Numbers").FirstOrDefaultAsync(x=> x.id == id);
第一个解决方案向Db发送两个请求(我认为如果正在跟踪实体,Find
方法不会发送请求);但是,我不确定第二个是如何工作的,因此我也不确定它是否有任何性能优势。我一直在想第一个解决方案可以更快,更有效。如果有人为我澄清这一点,我会很感激。
答案 0 :(得分:3)
这实际上取决于相关属性的数量,类型(引用或集合)以及第一种情况 - 如果它们已经加载或不加载。
假设您的实体具有N个参考导航属性和您要加载的M个集合导航属性。
使用Include
的方法将始终执行1 + M
db查询 - 一个用于实体+引用属性,使用JOIN
将数据检索到相应的表和在查询结果中作为列返回)和每个集合一个 - 无论实体和任何相关实体/集合是否已经加载。
显式加载的方法更具动态性。
如果实体未在上下文中加载,它将对该实体执行1 db查询,否则为0。
对于每个引用导航属性,如果引用的实体尚未在上下文中加载,则它将执行1 db查询,否则为0。
对于每个集合导航属性,如果集合未标记为已加载(db.Entry(entity).Collection(e => e.Collection).IsLoaded == false
),则它将执行1 db查询,否则为0。
最后,显式加载方法可以在0
和1 + N + M
db查询之间执行。
说了这么多,还不清楚哪一个更好。如果您使用的是相对短暂的DbContext
实例,因此不执行相关查询的可能性很低,我会采用Include
方法,因为它是确定性的。