簡體   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