gpt4 book ai didi

entity-framework-4 - 如何在多个 DbContext 类中只强制一个事务?

转载 作者:行者123 更新时间:2023-12-04 06:02:44 26 4
gpt4 key购买 nike

背景:
从 SO 的另一个问题来看,我有一个 Winforms 解决方案(财务),其中包含许多项目(解决方案的固定项目)。
现在,我的一位客户要求我“升级”解决方案并添加来自另一个 Winforms 解决方案 (HR) 的项目/模块。

我真的不想将这些项目作为现有财务解决方案的固定项目。为此,我正在尝试创建所有使用 MEF 加载 GUI、业务逻辑和数据层的插件。

问题:
我有一个带有外部上下文列表的上下文(为实现通用存储库模式而构建的 DbContext)(使用 MEF 加载-这些上下文表示来自每个插件的上下文,也具有通用存储库模式)。

假设我有这个:

public class MainContext : DbContext
{
public List<IPluginContext> ExternalContexts { get; set; }

// other stuff here
}


public class PluginContext_A : DbContext, IPluginContext
{ /* Items from this context */ }

public class PluginContext_B : DbContext, IPluginContext
{ /* Items from this context */ }

在已经加载的 MainContext 类中,我有两个外部上下文(来自插件)。

考虑到这一点,假设我有一个会影响 MainContext 和 PluginContext_B 的事务。

如何在一个事务中对两个上下文执行更新/插入/删除(工作统一)?

使用 IUnityOfWork,我可以为最后一项设置 SaveChanges(),但据我所知,我必须有一个上下文才能将其作为单个事务工作。

有一种使用 MSDTC (TransactionScope) 的方法,但这种方法很糟糕,我根本不打算使用它(也因为我需要在客户端和服务器上启用 MSDTC,而且我一直都有崩溃和泄漏)。

更新:
系统正在使用 SQL 2008 R2。永远不要吼叫。
如果可以以无法扩展到 MSDTC 的方式使用 TransactionScope,那很好,但我从未实现过。我一直使用 TransactionScope 它进入 MSDTC。根据 SO 上的另一篇文章,在某些情况下 TS 不会进入 MSDTC: check here .但我真的更喜欢采用其他方式而不是 TransactionScope ...

最佳答案

如果您使用多个上下文,每个上下文都使用单独的连接,并且您想在单个事务中将数据保存到这些上下文中,您必须使用 TransactionScope分布式事务 (MSDTC)。

您的链接问题并非如此,因为在这种情况下,第一个连接不会修改数据,因此可以在开始修改数据的连接之前将其关闭。在您的情况下,数据在需要两阶段提交和 MSDTC 的多个连接上同时修改。

您可以尝试通过在多个上下文之间共享单个连接来解决它,但这可能非常棘手。我不确定以下示例的可靠性如何,但您可以尝试一下:

using (var connection = new SqlConnection(connnectionString))
{
var c1 = new Context(connection);
var c2 = new Context(connection);

c1.MyEntities.Add(new MyEntity() { Name = "A" });
c2.MyEntities.Add(new MyEntity() { Name = "B" });

connection.Open();

using (var scope = new TransactionScope())
{
// This is necessary because DbContext doesnt't contain necessary methods
ObjectContext obj1 = ((IObjectContextAdapter)c1).ObjectContext;
obj1.SaveChanges(SaveOptions.DetectChangesBeforeSave);

ObjectContext obj2 = ((IObjectContextAdapter)c2).ObjectContext;
obj2.SaveChanges(SaveOptions.DetectChangesBeforeSave);

scope.Complete();

// Only after successful commit of both save operations we can accept changes
// otherwise in rollback caused by second context the changes from the first
// context will be already accepted = lost

obj1.AcceptAllChanges();
obj2.AcceptAllChanges();
}
}

上下文构造函数定义为:
public Context(DbConnection connection) : base(connection,false) { }

样本本身对我有用,但它有多个问题:
  • 上下文的首次使用必须在关闭连接的情况下完成。这就是我在打开连接之前添加实体的原因。
  • 我宁愿在事务之外手动打开连接,但也许不需要。
  • 保存更改都成功运行,Transaction.Current有空的分布式事务 ID,所以它应该仍然是本地的。
  • 保存要复杂得多,您必须使用 ObjectContext因为DbContext没有所有必要的方法。
  • 它不必在每种情况下都有效。甚至 MSDN 也声称:

  • Promotion of a transaction to a DTC may occur when a connection is closed and reopened within a single transaction. Because the Entity Framework opens and closes the connection automatically, you should consider manually opening and closing the connection to avoid transaction promotion.



    DbContext API 的问题在于,即使您手动打开它,它也会关闭并重新打开连接,因此如果 API 始终正确识别它是否在事务上下文中运行并且不关闭连接,这是一个开放的问题。

    关于entity-framework-4 - 如何在多个 DbContext 类中只强制一个事务?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8763248/

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