从DbContext中检索未提交的实体

时间:2013-02-25 18:02:51

标签: c# entity-framework dbcontext

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

考虑以下测试:

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

        Assert.AreEqual("testtenant", tenant.Name);
    }

测试失败,因为tenantnull

介于两者之间有很多具体的商业代码,但归结为:

在我的Repository课程中,方法GetTenantByName最后会调用GetAll方法。

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

    private IDbSet<TEntity> DbSet
    {
        get { return Context.Set<TEntity>(); }
    }

并且在扩展DbContext的类上我有以下方法:

    public new IDbSet<TEntity> Set<TEntity>() where TEntity : class
    {
        return base.Set<TEntity>();
    }

当我在return base.Set<TEntity>();上放置一个断点时,我可以看到该实体在存储库中可用(通过local属性)。


enter image description here


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

2 个答案:

答案 0 :(得分:3)

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

public virtual IEnumerable<DbEntityEntry> ChangedEntities
{
    get { return base.ChangeTracker.Entries().Where(e => e.State != EntityState.Unchanged); }
}

ChangeTrackerDbContext上的公共属性,因此您也可以从外部类访问此属性:

var dirtyEntities = myDbContext.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);

等等。

答案 1 :(得分:2)

就做如下简单的交易:

using (var scope = new TransactionScope(TransactionScopeOption.Required,
                        new TransactionOptions()
                        {
                            IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted
                        }))
{
    var employees = _context.Employees.ToList();
    scope.Complete();
}

如果你想同步获取数据,将 TransactionScopeAsyncFlowOption.Enabled 添加到上面的代码中:

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();