【问题标题】:EF6 Read uncommitted dataEF6 读取未提交的数据
【发布时间】:2025-11-28 13:05:01
【问题描述】:

我需要执行如下交易:

  1. 开始交易:这里我叫context.Database.BeginTransaction()(请注意这里的context不是我想读未提交的问题下面的那个)
  2. 保存联系人(使用存储过程完成):此 usp 也有交易。
  3. 根据联系人创建一些其他记录(使用 EF 应用程序端完成)
  4. 提交

我遇到的问题是,在第 3 步中,我需要从数据库中读取一些尚未提交的数据(从第 2 步开始)。我试过这样做,但它不起作用:

context.Database.ExecuteSqlCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;");
var contact = context.Contact.SingleOrDefault(x => x.ContactId == intId);
context.Database.ExecuteSqlCommand("SET TRANSACTION ISOLATION LEVEL READ COMMITTED;");

我让调试器运行并在获取contact 的位置暂停,但没有返回任何内容。

如果我在 SSMS (sql server mgmt studio) 中查询相同的记录,它会返回结果:

set transaction isolation level read uncommitted
select * from Contact c where c.ContactId = 9999

问题

  1. 如何使用 EF6 读取未提交的数据?一些在线搜索让我创建了一个自定义拦截器,但我真的需要吗?
  2. 许多文章建议不要读取未提交的数据,但我想不出另一种方法来实现这一点。有吗?

【问题讨论】:

  • 第 1 步究竟是什么?如果您执行var tr = context.Database.BeginTransaction();,那么使用相同context 的未来操作应该会看到该事务中未提交的更改。
  • @IvanStoev 它只是this.context.Database.BeginTransaction();,但这与问题中的上下文不同。
  • 我明白了。那就试试BeginTransaction(System.Data.IsolationLevel.ReadUncommitted),好像可以(快测)。
  • @IvanStoev 我试过了,但也没有用。你认为是因为有多个交易吗?一个是在应用程序中使用BeginTransaction 启动的,还有一个是在存储过程级别?换句话说,交易中的交易。
  • 可能是。在我的测试中,我使用了 2 个数据库上下文和 2 个(应用程序级别)事务。

标签: c# sql-server-2012 entity-framework-6


【解决方案1】:

我知道这个问题有点过时了,但只是希望它能对其他人有所启发。我的印象是在 ExecuteSqlCommand 中设置隔离级别是没有用的,因为它只会影响那条语句。 ExecuteSqlCommand 将启动它自己的事务。尝试以下操作,在您的其他事务范围内启动新的未提交读取事务:

Contact contact;
using (var trans = context.Database.BeginTransaction(IsolationLevel.ReadUncommitted))
{
    contact = context.Contact.SingleOrDefault(x => x.ContactId == intId);
    trans.Commit(); // not sure if this matters for a read
}

【讨论】:

    【解决方案2】:

    您可以尝试将数据库访问代码包装在 TransactionScope 中,如下所示:

    using (var scope = new TransactionScope(TransactionScopeOption.Required,
                    new TransactionOptions() { IsolationLevel = IsolationLevel.ReadUncommitted }))
    

    您是如何开始交易的?我问是因为如果代码流如您所描述的那样,步骤 2 和 3 中的所有操作都应该在同一个事务中完成,并且该事务应该能够看到同一事务中先前操作所做的任何更改。

    您也可以尝试使用 SQL Server Profiler 来观察数据库交互并查看是否正在创建其他(新)事务。

    如果您发布了执行步骤 1 到 4 的实际代码,这可能会有所帮助。

    【讨论】:

    • 我已经编辑了我的问题,是的,还有其他交易。
    • 当我尝试使用注入的 DBContext 时,我收到以下错误:TransactionScope 必须在创建它的同一线程上处理。
    • 只要我的 2 美分,如果您的所有逻辑都与数据库相关,我将使用 context.Database.BeginTransaction 而不是 TransactionScope。如果您在 EF 之外还有其他操作,那么我会使用 TransactionScope,因为这是一个 .NET 功能,而不是在数据库中创建的事务。