如何在实体框架中使用合并事务

本文关键字:合并 事务 框架 实体 | 更新日期: 2023-09-27 18:17:32

我有两个类。第一个表示主数据,第二个表示详细数据(它们通过外键连接)。由于详细记录需要已有的主记录,所以我必须先保存主记录。不幸的是,在保存详细数据的过程中可能会发生错误,所以我也应该回滚保存主数据,以防出现错误。

我有以下代码:

大师班:

 MyDataContext db=new MyDataContext();
 DetailData detail=new DetailData();
 using (var transaction= db.Database.BeginTransaction())
 {
  try
  {
   //db.Database.CommandTimeout = 10;
   db.SaveChanges();
   //saving details
   detail.SaveData(masterId);
   //on success
   transaction.Commit();
  }
  catch (Exception)
  {
   transaction.Rollback();
   throw;
  }
 }

细节类:

MyDataContext db;
DataItem dataItem;
public DetailData()
{
 db=new MyDataContext();
 dataItem=new DataItem();
 db.DataItem.Attach(dataItem);
}
public SaveData(int id)
{
  dataItem.Master_ID=id;
  db.SaveChanges();
}

由于Microsoft的最佳实践是按需使用DataContext,因此我不想将现有上下文传递到详细数据中。

通常,DataContext实例被设计为持续一个"单元"工作",无论您的应用程序如何定义该术语。DataContext是重量轻,制作成本不高。典型的LINQ to SQL应用程序在方法范围内创建DataContext实例或作为表示相关类的逻辑集的短寿命类的成员数据库操作。

不幸的是,我得到一个超时异常作为主事务尚未提交,我在不同的上下文对象上启动一个新的SaveChanges

如果我使用db.DataBase.UseTransaction并传递主类的事务,我会得到另一个关于属于另一个上下文的事务的异常。

那么我如何将主数据和详细数据的保存合并到一个工作事务中呢?

如何在实体框架中使用合并事务

也许我误解了你的问题,或者以下模式在你的情况下是不可能的,但通常你可以像这样添加主/详细记录:

var customer = new Customer();
dbContext.Customers.Add(customer);
var order = new Order();
order.Customer = customer;
dbContext.SaveChanges();

这假设您的CustomerOrder表与外键链接,并具有合适的EF导航属性(例如order.Customer)。

实体框架将以正确的顺序添加CustomerOrder记录,并将其添加到事务中的整个更新中,因此两个更新都成功,或者都不成功。


UPDATE:如果您有两个上下文,每个上下文都不知道另一个上下文所做的更改—如果您试图将对象从一个上下文添加到另一个上下文,则会得到错误。

我怀疑超时是因为每个上下文都试图在一个事务中执行一些数据库操作,而第一个事务阻塞了第二个事务。这并不是说你应该"结合"上下文,而是说你应该只有一个上下文。

您在问题中添加的引语是关于工作单元的。您的工作单元应该在逻辑上包含您正在进行的所有更改,包括对主记录和详细记录的更改。这才是重点。你应该只有一个上下文!:-)但是,您可以在上下文中创建事务

如果我理解正确的话,您的Master类正在尝试做两项工作:表示主数据记录并管理其持久性。Detail类也是如此。以这种方式违背关注点分离原则很可能会产生这样的问题。

使用储存库和工作单元模式将帮助您从管理事务的逻辑中分离实体。请参阅Tom Dykstra关于MVC中的存储库和工作单元模式的优秀教程。