C# 实体框架6.0:如果一个实体需要为另一个实体分配Id,我如何确保两个实体之间的事务完整性?

C# 实体框架6.0:如果一个实体需要为另一个实体分配Id,我如何确保两个实体之间的事务完整性?,c#,entity-framework,transactionscope,C#,Entity Framework,Transactionscope,关于在一个事务中多次调用dbContext.SaveChanges,我看到了许多问题和建议。 有人说这应该避免。这篇深入的文章真的值得一读 在我的特定场景中,实体B具有对实体A的Id引用 在一个创建场景中,我创建一个并调用savechanges以获得数据库分配的.Id。 然后我创建实体B,就像新的B(A.Id,…) 然后再次调用savechanges。在伪代码中可能是这样的 using(var tx = dbContext.BeginTransaction()) { var a = n

关于在一个事务中多次调用dbContext.SaveChanges,我看到了许多问题和建议。 有人说这应该避免。这篇深入的文章真的值得一读

在我的特定场景中,实体B具有对实体A的Id引用

在一个创建场景中,我创建一个并调用savechanges以获得数据库分配的.Id。 然后我创建实体B,就像新的B(A.Id,…) 然后再次调用savechanges。在伪代码中可能是这样的

using(var tx =  dbContext.BeginTransaction())
{
    var a = new A();
    dbContext.Add(a);  //a.Id is null
    dbContext.saveChanges(); // a.Id has now been initialized

    var b = new B(a.Id); //I want to create b in a valid state so a.Id  cannot be null
    dbContext.SaveChanges();
    tx.Commit();
}
(我知道伪代码缺少异常处理逻辑…)

为什么这是一个问题? 是因为无法回滚savechanges吗

我知道我可以重新建模,但这是不可能的,因为我们与一些遗留系统共享数据库,所以数据库不能轻易更改,如果可能的话

什么是替代解决方案?

请使用以下方法:

public class A
{
    [Key]
    public int Id { get; set; }

    public int BId { get; set; }

    [ForeignKey("BId")]
    public B B { get; set; }
}

public class B
{
    [Key]
    public int Id { get; set; }
}
然后只需将新创建的
B
分配给
A
的导航属性:

using (var transaction = dbContext.BeginTransaction())
{
    var a = new A();
    a.B = new B();
    dbContext.Add(a);
    dbContext.saveChanges();
    transaction.Commit();
}
使用这样的方法:

public class A
{
    [Key]
    public int Id { get; set; }

    public int BId { get; set; }

    [ForeignKey("BId")]
    public B B { get; set; }
}

public class B
{
    [Key]
    public int Id { get; set; }
}
然后只需将新创建的
B
分配给
A
的导航属性:

using (var transaction = dbContext.BeginTransaction())
{
    var a = new A();
    a.B = new B();
    dbContext.Add(a);
    dbContext.saveChanges();
    transaction.Commit();
}

考虑到实体框架确实支持显式事务,问题是什么?您似乎为一个功能编写了伪代码,而您的伪代码实际上调用了一个存在的方法,而您似乎错过了该功能。你费心看文件了吗?标题为“处理事务(EF6及以后)”。SaveChanges使用内部事务。更改分配已经是原子性的。真正的问题是什么?仅仅因为有人在某个地方写了你应该多次调用
SaveChanges
,并不意味着这是正确的。事实上,为什么你的代码要调用它两次??。如果你使用正确的关系,就没有理由分配ID。EF将识别新的/修改过的类,并生成SQL语句,这些语句将按注释的正确顺序插入新对象。是的,我读过关于交易的文章。在某些情况下,我可能更喜欢只按Id引用,而不使用对象关系。我的代码第一次调用SaveChanges是为了获得A的Id,以便初始化B。我有两个问题:1)我不清楚为什么调用savechages两次是不好的。2) 解决问题的其他方法。我很感激你给我的建议……考虑到实体框架确实支持显式事务,问题是什么?您似乎为一个功能编写了伪代码,而您的伪代码实际上调用了一个存在的方法,而您似乎错过了该功能。你费心看文件了吗?标题为“处理事务(EF6及以后)”。SaveChanges使用内部事务。更改分配已经是原子性的。真正的问题是什么?仅仅因为有人在某个地方写了你应该多次调用
SaveChanges
,并不意味着这是正确的。事实上,为什么你的代码要调用它两次??。如果你使用正确的关系,就没有理由分配ID。EF将识别新的/修改过的类,并生成SQL语句,这些语句将按注释的正确顺序插入新对象。是的,我读过关于交易的文章。在某些情况下,我可能更喜欢只按Id引用,而不使用对象关系。我的代码第一次调用SaveChanges是为了获得A的Id,以便初始化B。我有两个问题:1)我不清楚为什么调用savechages两次是不好的。2) 解决问题的其他方法。我很感谢您提出的建议..SaveChanges已经使用了一个事务。除此之外,使用导航属性是正确的处理方法relations@PanagiotisKanavos:correct-只是想保持代码与OPs“伪代码”类似:)SaveChanges已使用事务。除此之外,使用导航属性是正确的处理方法relations@PanagiotisKanavos:正确-只是想保持代码与OPs“伪代码”相似: