实体框架基线完整性

Posted

技术标签:

【中文标题】实体框架基线完整性【英文标题】:Entity Framework baseline integrity 【发布时间】:2017-02-17 13:40:51 【问题描述】:

我首先使用实体​​框架数据库,并且我有一个使用基线 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();

【问题讨论】:

看看sequences。 这是完美的,非常感谢。如果您将此添加为答案,我可以接受。 如果可行,请将您的解决方案作为答案发布。 【参考方案1】:

使用@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();
    

【讨论】:

以上是关于实体框架基线完整性的主要内容,如果未能解决你的问题,请参考以下文章

如何阻止实体框架尝试保存/插入子对象?

完整的IT项目开发流程

最新信息安全等级保护三级系统基线要求判分标准之应用安全

数据完整性约束——实体完整性参照完整性

例题

下列约束不属于实体完整性的是A.主键 B.标识列 C.外键 D. 以上不都是