[小技巧]EF Core中如何获取上下文中操作过的实体

原文地址:https://www.cnblogs.com/lwqlun/p/10576443.html

作者:Lamond Lu 

源代码:https://github.com/lamondlu/EFCoreFindSample

640?wx_fmt=jpeg

背景介绍

当我们在工作单元(UnitOfWork)中使用EF/EF Core的时候,为了要保持事务,一个用户操作只能调用一次SaveChange方法,但是有时候一个用户操作需要调用多个Repository,并且他们操作的实体是关联的。这时候在一个Repository中获取另外一个Repository中添加/修改/删除的实体就变成了一个问题。

问题说明

当前我们做一个学生管理系统,学生和班之间是多对多关系,一个学生可以属于多个班, 因此我们创建了如下的EF上下文。

640?wx_fmt=png

在用户界面上,我们允许用户在添加学生的时候,同时将学生分配到一个班级中。

因此我们的控制器代码如下:

640?wx_fmt=png

为了完成我们的业务,在StudentManagerAddStudent方法中,我们需要完成两步操作

•添加学生信息•将学生分配给指定班

640?wx_fmt=png

这里我们使用StudentRepositoryAddStudent方法来完成保存学生信息,使用GroupRepositoryAssignStudentToGroup方法来将学生分配给班级。

这里,其实不应该将保存学生信息和分配班级都放在这里,可以使用事件发布/订阅[3]将其分配班级的逻辑移动到别处。

针对保存学生信息的操作,代码很简单。

640?wx_fmt=png

但是当我们继续编写AssignStudentToGroup方法时就会遇到问题,我们该如何获取到前面方法中添加的Student实体?

这时候,有同学会去尝试

_dbContext.Students.Where(p=>p.StudentId = studentId)

你会发现它获取不到你想要的对象,原因是这条语句进行的是数据库查询,当前新增的Student对象还没有保存到数据库

那么如何解决这个问题呢?这里有2种解决方案

•从ChangeTracker上获取•使用Find方法获取

ChangeTracker上获取

ChangeTracker是EF/EF Core中的核心对象,在这个对象中记录了当前EF上下文,操作过的所有实体,实体状态及实体属性的变更。

ChangeTracker中的Entries泛型方法可以帮助我们获取到当前上下文中操作过的指定类型实体集合。

640?wx_fmt=png

但是这样写会出现一个问题,如果我想为一个数据库中已经存在的学生分配班级,调用这个方法就会出现问题,因为该实体还未加载到ChangeTracker中, 所以我们这里还需要使用_dbContext.Students.First方法进行数据库查询.

640?wx_fmt=png

至此,整个方法的修改就完成了。如果你觉着这种方式比较繁琐,请继续看下面的Find方法。

使用Find方法

EF/EF Core中其实还提供了一个Find方法,以下是该方法的方法签名。

640?wx_fmt=png

从这个Find方法的注释中,我们可以了解到,Find方法可以根据实体主键查询实体。但是它的优点是,它会优先去ChangeTracker中查找,如果查找不到才会生成查询语句,进行数据库查询。

由此,我们可以使用Find方法修改AssignStudentToGroup方法,看起来比之前的代码简化了不少

640?wx_fmt=png

References

[1]https://www.cnblogs.com/lwqlun/p/10576443.html
[2]https://github.com/lamondlu/EFCoreFindSample
[3] 事件发布/订阅: https://www.cnblogs.com/lwqlun/p/10468058.html


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值