前言
最近开发.net项目,持久层用的是EF框架,也是第一次使用这个框架,用这个框架的好处就是基于实体的开发,就是当代码中实体创建完成可以使用EF提供的code frist模式去创建数据表,也解决了项目部署是写脚本创建数据库的问题。使用这个框架也出现了一个问题就是实体和表中的字段是映射的,如果你用一个实体去更新数据时字段中有null值你的数据表中的对应的数据也会被赋值null,这里主要是体现在创建、更新时间这两个字段。
EF中核心类DbContext
Entity Framework (EF) 框架中的 DbContext
是一个重要的类,它是与数据库交互的主要入口点。
DbContext
表示一个数据库会话,它包含了连接数据库的信息,以及用于查询、插入、更新和删除数据的方法。它充当了数据访问层和对象关系映射 (ORM) 之间的桥梁,使得开发者能够以面向对象的方式操作数据库。
以下是一些常见的 DbContext
的用法和属性:
- 连接数据库:通过在
DbContext
的构造函数中指定连接字符串来连接到数据库。 - 定义实体集合:通过在
DbContext
中声明属性来表示数据库中的实体表,每个属性对应一个实体类型。 - 查询数据:使用
DbContext
提供的Set<T>()
方法来获取对应实体类型的查询接口,然后可以使用 LINQ 查询、延迟加载等方式来查询数据。 - 插入、更新和删除数据:使用
DbContext
提供的Add()
,Update()
,Remove()
等方法来执行对实体的插入、更新和删除操作。 - 事务管理:
DbContext
支持事务操作,你可以使用DbContext
的Database.BeginTransaction()
方法来启动事务,并使用SaveChanges()
方法来提交或回滚事务。 - 跟踪实体状态:
DbContext
会自动跟踪实体对象的状态,以便在调用SaveChanges()
方法时自动更新数据库。你可以使用DbContext
的Entry()
方法来访问实体的状态信息,并手动更改状态或属性的值。 - 数据库初始化:你可以通过重写
DbContext
的OnModelCreating()
方法来配置数据库模型和初始化数据,或者使用 Code First Migrations 来管理数据库迁移。
DbContext
是一个抽象类,你需要创建一个派生类来实现自己的上下文类,通常命名为YourDbContext
。这个派生类应该包含你的实体类作为属性,以便能够操作对应的数据库表。
请注意,DbContext
是一个轻量级对象,通常在使用后即可释放,以避免资源浪费。可以使用using
语句来确保DbContext
在不再需要时被正确地释放。
DbContext中的SaveChanges()方法
上面简单了解了这个核心类的功能,那么在项目中实际应用就是写一个继承了DBContext类的一个数据库会话类
关于这个类的实体项目的配置这里暂时不做说明,大家可以查询一下这个相关的配置有很多,就不在这里说了,直奔主题
重写SaveChanges()方法
为什么重写SaveChanges()方法呢?
重写 SaveChanges()
方法是为了在数据保存到数据库之前,对数据进行一些额外的处理或添加一些自定义的逻辑。
你想要在插入数据时为多个实体的逻辑删除字段添加默认值。而 SaveChanges()
方法是在数据保存到数据库之前被调用的。
通过重写 SaveChanges()
方法,你可以拦截保存操作,检查处于 EntityState.Added
状态的实体,并为它们的逻辑删除字段添加默认值。
这种方式使你能够在插入数据时对逻辑删除字段进行一致的处理,而无需在每个插入操作之前手动设置默认值。
重写 SaveChanges()
方法是 Entity Framework 提供的一种扩展机制,允许你在保存数据之前和之后执行自定义逻辑。你可以在重写方法中添加其他处理逻辑,如验证、日志记录、修改跟踪状态等。这样可以根据具体需求来扩展和定制 EF 的默认行为。
/// <summary>
/// 在执行提交时去将实体中需要插入的数据添加默认值
/// </summary>
private void insertDefault()
{
//获取实体中属于添加状态的实体
var addedEntities = ChangeTracker.Entries()
.Where(e => e.State == EntityState.Added);
foreach (var entityEntry in addedEntities)
{
//将实体中的
entityEntry.Property("is_delete").CurrentValue = false;
//判断实体是否创建时间属性,如果有则在插入时赋初值
var createTime = entityEntry.Entity.GetType().GetProperty("create_time");
if (createTime != null && createTime.CanWrite)
{
entityEntry.Property("create_time").CurrentValue = DateTime.Now;
}
//以上代码是具有通用性的
}
}
这段代码重写了 Entity Framework 中的 SaveChanges()
方法,并添加了两个额外的方法 insertDefault()
和 updateDefault()
。主要目的是在执行提交操作之前,为实体中需要插入的数据添加默认值。
具体的作用如下:
-
SaveChanges()
方法被重写,确保在保存数据之前执行自定义的逻辑。 -
insertDefault()
方法用于添加默认值到需要插入的实体数据中。首先,通过ChangeTracker.Entries()
方法获取处于EntityState.Added
状态的实体集合。然后,遍历每个实体并进行以下处理:- 设置逻辑删除字段
is_delete
的值为false
,将其设为未被逻辑删除的状态。 - 如果实体拥有
create_time
属性,将其设置为当前时间,以提供默认的创建时间值。 - 对于
RegistryCodeEntity
实体,设置is_overdue
字段的值为 0(byte
类型)。
- 设置逻辑删除字段
-
最后,调用基类的
SaveChanges()
方法来执行实际的数据保存操作,并将保存的结果返回。
注意点-Modified
通常使用了EF框架查询到的实体的时候我们直接进行修改数据然后执行 SaveChanges()
这方法,那么此时的这个实体状态就是Modified
的
在修改完实体后,如果没有显式设置实体的状态,而直接调用 SaveChanges()
方法,实体的状态将自动被识别为 Modified
。
当你修改实体的属性后,Entity Framework 会跟踪这些更改,并将实体的状态标记为 Modified
。在调用 SaveChanges()
方法时,EF 将会保存这些更改到数据库中。
因此,如果你在修改完实体后不去显式设置实体的状态,而是直接调用 SaveChanges()
方法,实体的状态会被自动识别为 Modified
,并将更改保存到数据库。
以下是一个示例:
var entity = dbContext.YourEntities.Find(entityId);
if (entity != null)
{
entity.Property1 = newValue1;
entity.Property2 = newValue2;
// 修改其他属性
dbContext.SaveChanges();
}
在上述示例中,我们修改了实体的多个属性,然后直接调用了 SaveChanges()
方法。由于我们没有显式设置实体的状态,EF 会自动将实体的状态标记为 Modified
,并将更改保存到数据库。
这是 Entity Framework 的默认行为,只要实体的属性被修改,EF 会自动识别并将实体状态设置为 Modified
。你不需要手动设置实体的状态,除非有特殊的需求或使用特定的跟踪方法来修改实体的状态。
其它状态下的实体如何操作
在 Entity Framework 中,EntityState
枚举表示实体对象在上下文中的不同状态。下面是 EntityState
枚举的常见值及其作用:
Detached
: 表示实体对象不受上下文跟踪,即实体未连接到上下文。这通常发生在实体是新创建的、已经被删除或从上下文中分离的情况下。Unchanged
: 表示实体对象与数据库中的对应记录保持一致,没有任何修改。Added
: 表示实体对象是一个新创建的对象,且尚未在数据库中进行插入操作。在调用SaveChanges()
方法后,实体将被插入到数据库中。Modified
: 表示实体对象的某些属性已被修改。在调用SaveChanges()
方法后,EF 将会更新数据库中相应的记录。Deleted
: 表示实体对象被标记为删除状态,即将从数据库中删除对应的记录。在调用SaveChanges()
方法后,EF 将会从数据库中删除相应的记录。
以上是EntityState
枚举的常见状态值及其作用。这些状态值用于跟踪实体对象在上下文中的状态,并指导 EF 在调用SaveChanges()
方法时执行相应的数据库操作。
通过检查实体对象的状态,你可以了解对象在上下文中的变化情况,并根据需要执行相应的操作,如插入、更新或删除数据。
在使用 Entity Framework 进行数据操作时,理解和正确使用实体状态是非常重要的,以确保数据的一致性和正确性。