查找实体然后附加关系数据与使用Include然后使用FirstOrDefault

时间:2017-06-04 14:56:18

标签: entity-framework entity-framework-core

考虑具有两个外键([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方法不会发送请求);但是,我不确定第二个是如何工作的,因此我也不确定它是否有任何性能优势。我一直在想第一个解决方案可以更快,更有效。如果有人为我澄清这一点,我会很感激。

1 个答案:

答案 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。

最后,显式加载方法可以在01 + N + M db查询之间执行。

说了这么多,还不清楚哪一个更好。如果您使用的是相对短暂的DbContext实例,因此不执行相关查询的可能性很低,我会采用Include方法,因为它是确定性的。