使用Entity Framework 7处理乐观并发的最佳方法

时间:2015-11-28 11:04:20

标签: asp.net-core entity-framework-core

我使用ASP.NET 5 rc1和Entity 7 rc1而不是coreclr,并带有示例代码首次迁移项目。

我正在研究如何管理实体中的并发性,但是我找不到有关实体7推荐的并发处理实践的任何好的更新信息。

我有几个实体,它们都实现了界面:

public interface IVersionedModel
{
    byte [] RowVersion { get; set; }
}

例如:

public class User : IVersionedModel
{
    public Guid UserId { get; set; }
    public string Name { get; set; }
    public byte[] RowVersion { get; set; }
}

而是将属性[Timestamp]添加到每个RowVersion列中,我更喜欢使用fluent配置,因此在我的DbContext中,我为每个实体指定了我希望该列作为行版本处理。

但实体7似乎不再支持选项.IsRowVersion() 但它有选项IsConcurrencyToken(),这应该足够了,但在代码中首先迁移它会生成一个可空的varbinary列,当插入/更新行时它不会自动递增

我想知道最好的办法是在更新或在数据库中插入实体时通过增加版本来显式管理每行的版本。 这是我的DbContext

public class AppDbContext : DbContext
{
    public AppDbContext() : base()
    {
    }

    public DbSet<User> Users { get; set; }
    public DbSet<Organization> Organizations { get; set; }
    public DbSet<Membership> Memberships { get; set; }

    public override int SaveChanges()
    {
        //increase entity version for concurrency purposes
        foreach(var dbEntityEntry in ChangeTracker.Entries()
            .Where(x => x.State == EntityState.Added || x.State == EntityState.Modified))
        {
            IVersionedModel entity = dbEntityEntry.Entity as IVersionedModel;
            if(entity != null)
            {
                //Increase byte[] RowVersion?
            }
        }
        return base.SaveChanges();
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<User>().Property(u => u.RowVersion).IsConcurrencyToken();
        modelBuilder.Entity<Organization>().Property(o => o.RowVersion).IsConcurrencyToken();
        modelBuilder.Entity<Membership>().Property(m => m.RowVersion).IsConcurrencyToken();
    }
}

基本上我的问题是,如何使用ASP.NET 5和Entity 7处理并发? 这是我第一次处理这件事,任何建议都会受到赞赏。

更新:感谢提供的链接https://stackoverflow.com/users/1922568/joe-audette我发现了一些答案,遗憾的是并非全部

根据http://docs.efproject.net/en/latest/modeling/concurrency.html#how-concurrency-tokens-work-in-ef 如果我们想要在属性上版本行或Timestamp注释,如果我们想要基于属性(而不是整行)的版本,我们似乎可以使用ConcurrencyCheck注释。

流畅的API仅允许使用.IsConcurrencyToken()

配置并发令牌

我还没有找到一种方法通过流畅的API来使用专用列对整行进行版本化(如果流畅的API允许.IsRowVersion(),那就太好了,但事实并非如此)

1 个答案:

答案 0 :(得分:3)

我已经创建了一个静态类来处理EF7 ModelBuilder的这个和其他缺失的功能(谨慎使用,未在生产环境中测试)

public static class SqlServerModelBuilderExtensions
{
    public static PropertyBuilder<decimal?> HasPrecision(this PropertyBuilder<decimal?> builder, int precision, int scale)
    {
        return builder.HasColumnType($"decimal({precision},{scale})");
    }

    public static PropertyBuilder<decimal> HasPrecision(this PropertyBuilder<decimal> builder, int precision, int scale)
    {
        return builder.HasColumnType($"decimal({precision},{scale})");
    }

    public static PropertyBuilder<byte[]> IsRowVersion(this PropertyBuilder<byte[]> builder)
    {
        return builder.HasColumnType("rowversion").IsConcurrencyToken().ValueGeneratedOnAdd();
    }
}