针对MySql中使用EFCore CodeFirst 自定义RowVersion并发字段的解决办法

依赖包版本:MySql.EntityFrameworkCore v5.0.3.1

RowVersion字段的作用:在增/删/改...数据时,先判断该数据的RowVersion字段是否发生改变来实现乐观锁的效果。

在SqlServer中,设置并发字段时可以在代码中采用byte[]类型字段来存储数据库中timestamp类型的数据;

但在MySql中,RowVersion需要应用程序赋值。这里存储Guid值实现版本号控制。

  1. 定义并发控制字段

    public class AdminEntity
        {
        	//对应MySql数据库中的字段类型是varbinary(4000)
            public byte[] RowVersion { get; set; }
        }
  2. 配置实体关系映射

    protected override void OnModelCreating(ModelBuilder modelBuilder)
           	{
    
                modelBuilder.Entity<AdminEntity>(entity =>
                {
                    entity.ForMySQLHasCharset("utf8");
                    entity.ForMySQLHasCollation("utf8_general_ci");
    
                    entity.ToTable("T_Admins");
    
                    entity.Property(e => e.RowVersion)
                        .HasColumnName("rowVersion")
                        .IsConcurrencyToken();//注意这里要使用IsConcurrencyToken()而不是IsRowVersion()
                });
    	}
    

      

  3. 重写数据库上下文的SaveChanges()方法

    public override int SaveChanges()
            {
        
        		//检查数据库更改
                this.ChangeTracker.DetectChanges();
    
        		//筛选新增/修改的实体对象
                var modifiedEntities = this.ChangeTracker
                    .Entries()
                    .Where(x => x.State == EntityState.Modified || x.State == EntityState.Added)
                    .Select(x => x.Entity)
                    .ToList();
                foreach (var entity in modifiedEntities)
                {
                    //存储一个新的Guid值
                    entity?.GetType().GetProperty("RowVersion")
                        ?.SetValue(entity, Encoding.Default.GetBytes(Guid.NewGuid().ToString()));
                }
                return base.SaveChanges();
            }
  4. 检查生成的Sql语句

  5. 查看数据库的数据

  6. 测试验证并发字段是否可用

    public void Test()
            {
                using (MyDbContext db = new MyDbContext())
                {
                    var admin1 = db.AdminSet.FirstOrDefault();
                    admin1.AdminName = "admin11";
                    using (zzmqDbContext db2 = new zzmqDbContext())
                    {
                        var admin2 = db2.AdminSet.FirstOrDefault();
                        admin2.AdminName = "admin22";
                        db2.SaveChanges();
                    }
                    db.SaveChanges();
                }
            }
  7. 执行结果

     ok,说明并发字段起作用了。

posted @ 2021-06-06 16:15  木节  阅读(490)  评论(0编辑  收藏  举报