C# 从DbContext检索未提交的实体

C# 从DbContext检索未提交的实体,c#,entity-framework,dbcontext,C#,Entity Framework,Dbcontext,如何从DbContext检索未提交的实体 考虑以下测试: [Test] public void AddAndRetrieveUncommittedTenant() { _tenantRepository.Create("testtenant"); var tenant = _tenantRepository.GetTenantByName("testtenant"); Assert.AreEqual("testtenant

如何从DbContext检索未提交的实体

考虑以下测试:

    [Test]
    public void AddAndRetrieveUncommittedTenant()
    {
        _tenantRepository.Create("testtenant");
        var tenant = _tenantRepository.GetTenantByName("testtenant");

        Assert.AreEqual("testtenant", tenant.Name);
    }
测试失败,因为
tenant
null

在这两者之间有很多特定的业务代码,但归根结底是:

在我的
Repository
类中,方法
GetTenantByName
最后调用
GetAll
方法

    public IQueryable<TEntity> GetAll()
    {
        return DbSet.AsQueryable();
    }

    private IDbSet<TEntity> DbSet
    {
        get { return Context.Set<TEntity>(); }
    }
当我在
return base.Set()上设置断点时我可以看到实体在存储库中可用(通过
local
属性)




如何从存储库中检索未提交的实体?

我使用从
DbContext
派生的类,并添加以下方法来访问已更改的实体。这还应该告诉您如何访问
DbContext
中更改的实体:

public virtual IEnumerable<DbEntityEntry> ChangedEntities
{
    get { return base.ChangeTracker.Entries().Where(e => e.State != EntityState.Unchanged); }
}
或者,如果要查找已添加/修改的实体等,您可以获得更具体的信息:

var addedEntities = myDbContext.ChangeTracker.Entries().Where(e => e.State == EntityState.Added);
var modifiedEntities = myDbContext.ChangeTracker.Entries().Where(e => e.State == EntityState.Modified);

依此类推。

只需执行以下简单事务:

using (var scope = new TransactionScope(TransactionScopeOption.Required,
                        new TransactionOptions()
                        {
                            IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted
                        }))
{
    var employees = _context.Employees.ToList();
    scope.Complete();
}
如果要同步获取数据,请添加TransactionScopeAsyncFlowOption。已启用上述代码:

using (var scope = new TransactionScope(TransactionScopeOption.Required,
                        new TransactionOptions()
                        {
                            IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted
                        },
                        TransactionScopeAsyncFlowOption.Enabled))
{
    var employees = await _context.Employees.ToListAsync();
    scope.Complete();
}
为了简单起见,您可以为上述事务使用自己的扩展方法:

public static async Task<List<T>> ToListWithNoLockAsync<T>(this IQueryable<T> query, CancellationToken cancellationToken = default)
{
    List<T> result = default;
    using (var scope = new TransactionScope(TransactionScopeOption.Required,
                            new TransactionOptions()
                            {
                                IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted
                            },
                            TransactionScopeAsyncFlowOption.Enabled))
    {
        result = await query.ToListAsync(cancellationToken);
        scope.Complete();
    }
    return result;
}

嘿,布莱恩,可能就是这个。我试图从
IEnumerable
IEnumerable
,这似乎比我想象的要难。
DbEntityEntry
是我实体周围的某种无形包装,我似乎无法将其取出(好吧,并非编译器同意,运行时我甚至可以看到我实体的属性)@bas,是的,EF将您的实体包装在某种动态代理中,这种代理不一定可以分配给原始实体类型(我已经找到)。你到底想完成什么?
DbContext
仍将具有实际实体(处于其已更改状态),因此您可以使用
ChangeTracker
获取已修改实体的Id,然后从
DbContext
检索实际实体吗?第一步现在完成,我可以使用您建议的方法检索处于添加状态的实体。问题是我当前的接口是
IQueryable GetAll()
,我使用它来
包含导航属性。如果我将代码更改为
IEnumerable
,我就会陷入剩下的业务代码中。但是,好消息是,你的部分似乎起作用了,所以我会接受答案并开始困惑:)。谢谢布莱恩!什么是“未提交的实体”?我认为问题不在于从数据库中读取未提交的数据。
using (var scope = new TransactionScope(TransactionScopeOption.Required,
                        new TransactionOptions()
                        {
                            IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted
                        },
                        TransactionScopeAsyncFlowOption.Enabled))
{
    var employees = await _context.Employees.ToListAsync();
    scope.Complete();
}
public static async Task<List<T>> ToListWithNoLockAsync<T>(this IQueryable<T> query, CancellationToken cancellationToken = default)
{
    List<T> result = default;
    using (var scope = new TransactionScope(TransactionScopeOption.Required,
                            new TransactionOptions()
                            {
                                IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted
                            },
                            TransactionScopeAsyncFlowOption.Enabled))
    {
        result = await query.ToListAsync(cancellationToken);
        scope.Complete();
    }
    return result;
}
var employees = dbContext.Employees
                          .AsNoTracking()
                          .Where(a => a.IsDelete == false)
                          .ToListWithNoLockAsync();