2017-02-17 67 views
0

我正在使用實體框架數據庫,並且我有一個使用基線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之前,保存沒有完成。

  • 的方法可以一次必須由基線IDS連接在一起增加了許多項目
  • 這必須是一個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(); 
} 
+0

看一看[序列](http://stackoverflow.com/questions/27077461/how-to-get-next-value-of-sql-server-sequence-in-entity-framework) 。 –

+0

這很完美,非常感謝。如果你添加這個作爲答案,我可以接受它。 – Joe

+0

如果有效,只需發佈​​您的解決方案作爲答案。 –

回答

0

使用@Steve格林的建議下,我能夠使用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(); 
    } 
}