如何从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>(); }
}
并且在扩展DbContext
的类上我有以下方法:
public new IDbSet<TEntity> Set<TEntity>() where TEntity : class
{
return base.Set<TEntity>();
}
当我在return base.Set<TEntity>();
上放置一个断点时,我可以看到该实体在存储库中可用(通过local
属性)。
如何从我的存储库中检索未提交的实体?
答案 0 :(得分:3)
我使用从DbContext
派生的类,并添加以下方法来访问实体已更改的内容。这也应该告诉您如何访问DbContext
中已更改的实体:
public virtual IEnumerable<DbEntityEntry> ChangedEntities
{
get { return base.ChangeTracker.Entries().Where(e => e.State != EntityState.Unchanged); }
}
ChangeTracker
是DbContext
上的公共属性,因此您也可以从外部类访问此属性:
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();