繁体   English   中英

实体框架基准完整性

[英]Entity Framework baseline integrity

我首先使用Entity Framework数据库,并且有一个表使用基线ID存储历史值。 我们使用基线ID在此表上存储父/子链接。 以下专栏对此设计进行了补充:-

  • ID int(主键-唯一)
  • BaselineId int(不是唯一的,但是对同一项目进行唯一的身份修订)
  • ParentBaselineId int可为空(指链接实体的基线,无FK)
  • 最新位(指示这是系列中的最新基线)

为清楚起见示例数据

Id  BaselineId  ParentBaselineId Latest
1   1           NULL             0
2   1           NULL             1
3   2           1                0
4   2           1                1

这显示了两个项目,每个项目都有两个修订版本。 基准1是基准2的父级。

我的问题是,出于下面列出的原因,我在C#中查找了下一个可用基线,并手动指定了要保存的BaselineId / ParentBaselineId。 当两个用户同时触发此方法时,他们将保存相同的基准ID,因为在第二个用户查找下一个可用的基准ID之前,保存尚未完成。

  • 该方法可以一次添加许多必须通过基准ID链接在一起的项目
  • 这必须是单个SQL事务,以便可以在发生错误时完全回滚
  • SQL触发器不能用于设置基线,因为需要提前使用基线来指示关系

我应该采取什么措施来确保两个用户同时运行该方法不会使用相同的基线?

我的C#看起来像这样

using (var tx = new TransactionScope())
{
    using (var context = new DbContext(connectionString))
    {
        int baseline = context.MyTable.Max(e => e.BaselineId);
        context.MyTable.Add(new MyTable() {BaselineId = baseline + 1, Latest = true});
        context.MyTable.Add(new MyTable() { BaselineId = baseline + 2, ParentBaselineId = baseline + 1, Latest = true });
        context.SaveChanges();
    }

    tx.Complete();
}

根据@Steve Greene的建议,我可以使用SQL序列。 在数据库中创建新序列并设置起始值以匹配现有数据后,我将代码更新为以下内容。

public long NextBaseline(DbContext context)
{
    DataTable dt = new DataTable();
    var conn = context.Database.Connection;
    var connectionState = conn.State;
    try
    {
        if (connectionState != ConnectionState.Open)
            conn.Open();
        using (var cmd = conn.CreateCommand())
        {
            cmd.CommandText = "SELECT NEXT VALUE FOR MySequence;";
            using (var reader = cmd.ExecuteReader())
            {
                dt.Load(reader);
            }
        }
    }
    catch (Exception ex)
    {
        throw new HCSSException(ex.Message, ex);
    }
    finally
    {
        if (connectionState != ConnectionState.Open)
            conn.Close();
    }
    return Convert.ToInt64(dt.AsEnumerable().First().ItemArray[0]);
}

public void Save()
{
    using (var tx = new TransactionScope())
    {
        using (var context = new DbContext(connectionString))
        {
            var parent = new MyTable() { BaselineId = NextBaseline(context), Latest = true };
            var child = new MyTable() { BaselineId = NextBaseline(context), ParentBaselineId = parent.BaselineId, Latest = true }
            context.MyTable.Add(parent);
            context.MyTable.Add(child);
            context.SaveChanges();
        }

        tx.Complete();
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM