gpt4 book ai didi

entity-framework-4 - EF4 代码优先 + SQL Server CE : save bidirectional reference atomically

转载 作者:行者123 更新时间:2023-12-04 12:34:53 24 4
gpt4 key购买 nike

我想保存一些具有双向关系的实体(两端的导航属性)。这是通过两次调用 context.SaveChanges() 来完成的。 .

[关于我的模型、映射以及我如何到达那里的完整细节在折叠之后。]

public void Save(){

var t = new Transfer();
var ti1 = new TransferItem();
var ti2 = new TransferItem();

//deal with the types with nullable FKs first
t.TransferIncomeItem = ti1;
t.TransferExpenseItem = ti2;

context.Transfers.Add(t);
context.Operations.Add(ti1);
context.Operations.Add(ti2);

//save, so all objects get assigned their Ids
context.SaveChanges();

//set up the "optional" half of the relationship
ti1.Transfer = t;
ti2.Transfer = t;
context.SaveChanges();
}

一切都很好,但是如果在两次调用 SaveChanges() 之间发生雷击,如何确保数据库不会不一致? ?

输入 TransactionScope ...
public void Save(){
using (var tt = new TransactionScope())
{
[...same as above...]
tt.Complete();
}
}

...但是在第一次调用 context.SaveChanges() 时失败了出现此错误:

The connection object can not be enlisted in transaction scope.



This questionthis MSDN article建议我明确登记交易...
public void Save(){
using (var tt = new TransactionScope())
{
context.Database.Connection.EnlistTransaction(Transaction.Current);

[...same as above...]
tt.Complete();
}
}

...同样的错误:

The connection object can not be enlisted in transaction scope.



这里的死胡同...让我们采用不同的方法 - 使用显式事务。
public void Save(){
using (var transaction = context.Database.Connection.BeginTransaction())
{
try
{
[...same as above...]
transaction.Commit();
}
catch
{
transaction.Rollback();
throw;
}
}

仍然没有运气。这一次,错误信息是:

BeginTransaction requires an open and available Connection. The connection's current state is Closed.



我该如何解决?

TL; DR 详细信息

这是我的简化模型:引用两个操作 (TransferItem) 的事务,这些操作引用回事务。 这是一个 1:1 映射 在 Transfer 和它的两个项目中的每一个之间。

我想要的是确保这些是 以原子方式保存 添加新时 Transfer .

这是我走过的路,也是我卡住的地方。

该模型:
public class Transfer
{
public long Id { get; set; }
public long TransferIncomeItemId { get; set; }
public long TransferExpenseItemId { get; set; }
public TransferItem TransferIncomeItem { get; set; }
public TransferItem TransferExpenseItem { get; set; }
}

public class Operation {
public long Id;
public decimal Sum { get; set; }
}

public class TransferItem: Operation
{
public long TransferId { get; set; }
public Transfer Transfer { get; set; }
}

我想将此映射保存到数据库 (SQL CE)。
public void Save(){
var t = new Transfer();
var ti1 = new TransferItem();
var ti2 = new TransferItem();
t.TransferIncomeItem = ti1;
t.TransferExpenseItem = ti2;

context.Transfers.Add(t);
context.Operations.Add(ti1);
context.Operations.Add(ti2);
context.SaveChanges();
}

这在我面前吹来了错误:

"Unable to determine a valid ordering for dependent operations. Dependencies may exist due to foreign key constraints, model requirements, or store-generated values."



这是一个先有鸡还是先有蛋的问题。我无法使用不可为空的外键保存对象,但为了填充外键,我需要先保存对象。

看着 this question看来我必须放松我的模型,并且:
  • 在关系的至少一侧具有可为空的 FK
  • 首先保存这些对象
  • 建立关系
  • 再次保存。

  • 像这样:
    public class TransferItem: Operation
    {
    public Nullable<long> TransferId { get; set; }
    [etc]
    }

    此外,这里是映射。 Morteza Manavi 的 article on EF 1:1 relationships真的很有帮助。基本上,我需要与指定的 FK 列创建一对多关系。 'CascadeOnDelete(false)' 处理关于多个级联路径的错误。 (DB 可能会尝试删除 Transfer 两次,每个关系一次)
            modelBuilder.Entity<Transfer>()
    .HasRequired<TransferItem>(transfer => transfer.TransferIncomeItem)
    .WithMany()
    .HasForeignKey(x => x.TransferIncomeItemId)
    .WillCascadeOnDelete(false)
    ;

    modelBuilder.Entity<Transfer>()
    .HasRequired<TransferItem>(transfer => transfer.TransferExpenseItem)
    .WithMany()
    .HasForeignKey(x => x.TransferExpenseItemId)
    .WillCascadeOnDelete(false)
    ;

    用于保存实体的更新代码位于问题的开头。

    最佳答案

    为了完成这项工作,我必须添加更流畅的映射,以明确创建 TransferItem 的可选映射。在 Transfer类,以及使 FK 在 TransferItem 上可以为空.

    一旦映射被修复,我将所有这些都包装在一个 TransactionScope 中没有问题。

    这是整个控制台应用程序:

      public class Transfer
    {
    public long Id { get; set; }
    public long TransferIncomeItemId { get; set; }
    public long TransferExpenseItemId { get; set; }
    public TransferItem TransferIncomeItem { get; set; }
    public TransferItem TransferExpenseItem { get; set; }
    }

    public class Operation
    {
    public long Id { get; set; }
    public decimal Sum { get; set; }
    }

    public class TransferItem : Operation
    {
    public long? TransferId { get; set; }
    public Transfer Transfer { get; set; }
    }

    public class Model : DbContext
    {

    public DbSet<Transfer> Transfers { get; set; }
    public DbSet<Operation> Operations { get; set; }
    public DbSet<TransferItem> TransferItems { get; set; }

    protected override void OnModelCreating( DbModelBuilder modelBuilder )
    {
    modelBuilder.Entity<Transfer>()
    .HasRequired( t => t.TransferIncomeItem )
    .WithMany()
    .HasForeignKey( x => x.TransferIncomeItemId )
    .WillCascadeOnDelete( false );

    modelBuilder.Entity<Transfer>()
    .HasRequired( t => t.TransferExpenseItem )
    .WithMany()
    .HasForeignKey( x => x.TransferExpenseItemId )
    .WillCascadeOnDelete( false );

    modelBuilder.Entity<TransferItem>()
    .HasOptional( t => t.Transfer )
    .WithMany()
    .HasForeignKey( ti => ti.TransferId );
    }
    }

    class Program
    {
    static void Main( string[] args )
    {

    using( var scope = new TransactionScope() )
    {
    var context = new Model();

    var ti1 = new TransferItem();
    var ti2 = new TransferItem();

    //deal with the types with nullable FKs first
    context.Operations.Add( ti1 );
    context.Operations.Add( ti2 );
    var t = new Transfer();
    context.Transfers.Add( t );
    t.TransferIncomeItem = ti1;
    t.TransferExpenseItem = ti2;
    //save, so all objects get assigned their Ids
    context.SaveChanges();

    //set up the "optional" half of the relationship
    ti1.Transfer = t;
    ti2.Transfer = t;
    context.SaveChanges();
    scope.Complete();
    }

    }
    }

    运行时生成此数据库:

    enter image description here

    这个输出:

    enter image description here

    关于entity-framework-4 - EF4 代码优先 + SQL Server CE : save bidirectional reference atomically,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12212418/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com