4

我想设置实体框架,以便 SavesChanges() 不会用 BEGIN 和 COMMIT 包装所有生成的 SQL。我从一个相关的SO 问题中发现了这个建议:

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

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

接下来我开始翻阅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)设置为空。强制 EF 看不到交易并做与我想要的相反的事情并创建新交易。

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

谢谢!

4

1 回答 1

0

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

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

问题是你为什么这么想禁用交易?

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

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

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

于 2015-01-09T04:23:35.790 回答