C# 使用EF、多次选择或使用include时,哪个更好?
我有两个实体,一个是C# 使用EF、多次选择或使用include时,哪个更好?,c#,entity-framework,C#,Entity Framework,我有两个实体,一个是盒子,另一个是网球。在tabletennis中有一个外键BoxID,也就是说,tennis必须在框中,而框是tennis的集合 既然我知道了网球ID,我需要检查网球所属的框的名称。我有两个选择 选项A:首先在网球表中找到此网球的属性,获取框ID,然后转到框表以查找框的属性 var tennisId = 12345; // Option A: var tennis = await dbContext.TennisTable .SingleOrDefaultAs
盒子
,另一个是网球
。在tabletennis
中有一个外键BoxID
,也就是说,tennis
必须在框中,而框是tennis
的集合
既然我知道了网球ID,我需要检查网球所属的框的名称。我有两个选择
选项A:首先在网球
表中找到此网球
的属性,获取框ID
,然后转到框
表以查找框
的属性
var tennisId = 12345;
// Option A:
var tennis = await dbContext.TennisTable
.SingleOrDefaultAsync(t => t.Id == tennisId);
var box = await dbContext.BoxTable
.SingleOrDefaultAsync(t => t.Id == tennis.BoxID);
return box.Name;
// Option B:
var tennis = await dbContext.TennisTable
.Include(t => t.Box);
.SingleOrDefaultAsync(t => t.Id == tennisId);
return tennis.Box.Name;
选项B:直接使用EF-Core
的Include
语法查找tentiles
及其所属的框,以获取框的属性
var tennisId = 12345;
// Option A:
var tennis = await dbContext.TennisTable
.SingleOrDefaultAsync(t => t.Id == tennisId);
var box = await dbContext.BoxTable
.SingleOrDefaultAsync(t => t.Id == tennis.BoxID);
return box.Name;
// Option B:
var tennis = await dbContext.TennisTable
.Include(t => t.Box);
.SingleOrDefaultAsync(t => t.Id == tennisId);
return tennis.Box.Name;
在大规模实践中,上述两种方法中哪一种具有更大的性能优势
大规模
意味着在实际用例中问题可能要复杂得多。盒子
和网球
的数量可能是数十亿。两者都不是。这里不需要Include
语句
当您想检索其他相关实体时,应使用Include
语句。但这不是你想要的:
我需要核对一下这个网球所属盒子的名称
只需使用框
对象即可读取其名称。您不需要加载任何其他实体
var boxName = db.TennisTable
.Where(t => t.Id == tennisId)
.Select(t => t.Box.Name)
.Single();
如果需要在不引发异常的情况下说明网球对象可能不存在,请使用SingleOrDefault()
而不是Single()
换言之:
- 查找具有此ID的所有网球对象。我们知道只有一个,但是通过使用
Where
而不是Single
,EF还没有查询数据库,它可以继续使用IQueryable
- 对于所有找到的条目,选择其框的名称。同样,我们知道有一个条目,但是EF仍然不会实例化查询,因为您还没有枚举
IQueryable
- 取第一个结果。我们知道这是唯一的结果,但现在EF将通过一个(组合)调用而不是两个单独的调用来访问数据库
如果您使用了Include
logic,您将检索整个网球和拳击场对象。我的答案只检索框名,这大大减少了数据库和应用程序之间的数据传输大小
如果您使用了两个呼叫,您将同时加载网球和拳击对象和,您将不得不执行两个呼叫,这意味着由于额外的网络呼叫而增加了数据传输大小,降低了性能。。这里不需要Include
语句
当您想检索其他相关实体时,应使用Include
语句。但这不是你想要的:
我需要核对一下这个网球所属盒子的名称
只需使用框
对象即可读取其名称。您不需要加载任何其他实体
var boxName = db.TennisTable
.Where(t => t.Id == tennisId)
.Select(t => t.Box.Name)
.Single();
如果需要在不引发异常的情况下说明网球对象可能不存在,请使用SingleOrDefault()
而不是Single()
换言之:
- 查找具有此ID的所有网球对象。我们知道只有一个,但是通过使用
Where
而不是Single
,EF还没有查询数据库,它可以继续使用IQueryable
- 对于所有找到的条目,选择其框的名称。同样,我们知道有一个条目,但是EF仍然不会实例化查询,因为您还没有枚举
IQueryable
- 取第一个结果。我们知道这是唯一的结果,但现在EF将通过一个(组合)调用而不是两个单独的调用来访问数据库
如果您使用了Include
logic,您将检索整个网球和拳击场对象。我的答案只检索框名,这大大减少了数据库和应用程序之间的数据传输大小
如果您使用了两个调用,那么您将同时加载tennis和box对象和,您将不得不执行两个调用,这意味着由于额外的网络调用而增加了数据传输大小,并且降低了性能。定义:大规模
如果您能够提供一个到多个可能的调用,那将是非常棒的。如果你想用你的代码解决已经存在的问题,那么请发布代码。展望未来在这里是无关紧要的。@FCin:虽然选项应该与代码示例一起给出,但问题不在于如何展望未来,而在于认识到有多种方法可以做到这一点,而不知道哪种方法更好。OP已经完成了提出这两种方法的准备工作。定义:large-scale
如果您能为许多可能的问题提供解决方案,那就太棒了。如果你想用你的代码解决已经存在的问题,那么请发布代码。展望未来在这里是无关紧要的。@FCin:虽然选项应该与代码示例一起给出,但问题不在于如何展望未来,而在于认识到有多种方法可以做到这一点,而不知道哪种方法更好。OP已经完成了提出这两种方法的准备工作。如果我都需要网球的名字和盒子的名字呢?假设你只需要名字:。选择(t=>new{BoxName=t.box.name,TennisName=t.N