【问题标题】:Entity Framework 5 without transactions没有事务的实体框架 5
【发布时间】:2013-07-15 18:52:19
【问题描述】:

我想设置实体框架,以便 SavesChanges() 不会用 BEGIN 和 COMMIT 包装其生成的所有 SQL。我从一个相关的SO question 那里得到了这个建议:

using( var transation = new TransactionScope(TransactionScopeOption.Suppress) )
{
    ObjectContext.SaveChanges();
}

但这对我不起作用。我们正在使用 MYSQL 连接器,所以我确实通过逐步浏览源代码进行了一些挖掘,我发现 EntityFramework 是要求创建新事务的那个,而不是连接器的错误,请参见以下内容堆栈跟踪。

接下来我开始翻阅EF的源代码(EF 6是开源的,相关代码在反编译器中看起来是一样的)

        var needLocalTransaction = false;
        var connection = (EntityConnection)Connection;
        if (connection.CurrentTransaction == null
            && !connection.EnlistedInUserTransaction
            && _lastTransaction == null)
        {
            needLocalTransaction = startLocalTransaction;
        }

        ...


        if (needLocalTransaction)
        {
            localTransaction = connection.BeginTransaction();
        }

好的,如果交易不存在,它会自己创建一个。进一步了解如何在 EF 中设置当前事务,我将了解 EF 设置连接的代码

            var currentTransaction = Transaction.Current;

            EnsureContextIsEnlistedInCurrentTransaction(
                currentTransaction,
                () =>
                {
                    Connection.Open();
                    _openedConnection = true;
                    _connectionRequestCount++;
                    return true;
                },
                false);

这似乎是“TransactionScopeOption.Suppress”行发挥作用的唯一地方,但所做的只是将环境事务 (Transaction.Current) 设置为 null。强制 EF 看不到交易并做与我想要的相反的事情并创建新交易。

在 EF 5 中关闭事务是否有其他人运气好,或者是我破解和构建我自己版本的 sql 连接器的唯一解决方案?

谢谢!

【问题讨论】:

  • 无论您尝试做什么,都可能做错了。禁用 EF 的内部事务将使 EF 内部代码在操作后处于未知状态。只是不要这样做。而是描述您要解决的问题。最好通过为每个工作单元声明一个新的上下文来使用 EF。一个工作单元应该由最少数量的操作组成,如果回滚,这些操作仍然会使业务数据保持逻辑正确的状态。创建订单可以是独立于向订单添加行项目的工作单元。这最适用于 MVVM 架构。
  • @Kurian,你对未知状态是正确的,所以我不会对所有 EF 连接都这样做。但是,我们有很多事件,每个事件都执行一次插入,并且每个事件都有它们不需要的事务的额外性能开销。
  • 我可以盲目地声明,数据库操作不是您所做工作的瓶颈。这是不太可能的。事实上,每个插入语句都应该在一个事务中,并在它正在读取和写入的任何表上进行适当的锁定等。DBMS 就是为此而设计的。您执行的每条语句都会发生各种隐式事务和锁定。 EF 交易可以忽略不计。如果缺乏性能,则说明您存在代码质量问题。
  • @Kurian,我怀疑你是对的。但是,我们有一个跟踪工具,显示 BEGIN 语句的时间为 5 毫秒,实际的 sql 为 15 毫秒。因此,取出BEGIN可能会使sql运行20ms,但是如果不关闭EF中的内部事务,我将无法尝试......
  • 这样想:每条语句都在某种事务中执行。显式声明事务仅使您能够移动端点以覆盖多行。每个单行语句都有隐式事务和锁。延迟更有可能是客户端。 EF很重,每次操作都很慢。显式事务可能会减慢 EF 代码,但不会减慢数据库引擎。最好将一些内容移动到通过上下文执行的普通 SQL 语句中。

标签: entity-framework mysql-connector


【解决方案1】:

EF5 被硬编码以将 INSERTS 和 UPDATES 包装到事务中。在几乎所有情况下,这都是批量写入多个实体时所期望的行为。

如果您想改变这一点,您必须自己编写新代码,将其编译为适当的 DLL,然后引用新代码。要解决一个非常重要的安全功能需要做很多工作。不推荐。

问题是您为什么这么想禁用事务?

它会导致性能问题吗?您是否发现交易的额外安全性不利于业务流程?

听起来您不在乎是否发生写入丢失、幻读等情况(我假设这是因为您想一起跳过事务),这是个坏主意。

如果情况并非如此(我希望如此)并且您担心性能,那么您的事务级别隔离可能对于您想要的来说太高了?您可能希望将其他调用包装在设置低得多(安全性较低,但锁定较少,因此性能更好)隔离级别的事务中,例如未提交读?

【讨论】:

  • 谢谢乔恩,这是不久前的事了。从记忆中,我的问题是写入性能缓慢,并且我误解了我的跟踪工具归因于 BEGIN 和 END 语句的时间。 IIRC 我们最终选择了一个 microORM 解决方案,它允许我们编写诸如 UPDATE WHERE 语句之类的东西,从而成倍地提高性能
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多