dbcontext 跟蹤行為設定為 NoTracking,但我在測驗中仍然失敗。
與 EF 提供的 IdentityDbContext 相比,此背景關系中的 BaseDbContext 沒有任何相關代碼。也和 BaseUser 一樣,基本上只有 IdentityUser。
創建 DbContext 的方法:
public static T GetDbContext<T>()
where T : BaseDbContext<BaseUser<Guid>>
{
var optionBuilder = new DbContextOptionsBuilder<T>();
optionBuilder.UseInMemoryDatabase(Guid.NewGuid().ToString());
optionBuilder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
var obj = Activator.CreateInstance(typeof(T), optionBuilder.Options);
if (obj == null)
{
throw new SystemException(typeof(T) " was null!");
}
var ctx = (T)obj;
ctx.Database.EnsureDeleted();
ctx.Database.EnsureCreated();
return ctx;
}
失敗的測驗:
[Fact]
public async void Test_UpdateSingle()
{
var dbContext = DbContextFactory.GetDbContext<SimpleDbContext>();
var uow = UowFactory.GetUow<SimpleUow, SimpleDbContext>(dbContext);
var id1 = Guid.NewGuid();
var name1 = Guid.NewGuid().ToString();
var testEntity1 = new DalSimpleEntity
{
Id = id1,
Name = name1
};
uow.SimpleRepo.Add(testEntity1);
await uow.SaveChangesAsync();
var newName = Guid.NewGuid().ToString();
testEntity1.Name = newName;
//Fails here:
uow.SimpleRepo.Update(testEntity1);
await uow.SaveChangesAsync();
Assert.Single(await uow.SimpleRepo.GetAllAsync());
var getEntity1 = await uow.SimpleRepo.FirstOrDefaultAsync(id1);
Assert.Equal(newName, getEntity1?.Name);
}
UnitOfWork 用于將其用作 dbcontext 之上的層。SaveChanges 方法直接呼叫 DbContext savechanges。
UnitOfWork 還包含對 Repository 的參考。
SimpleRepo 派生自 BaseRepository。SimpleRepo 中沒有任何更改。
public abstract class BaseRepository<TDbContext, TEntityIn, TEntityOut> : BaseRepositoryWebApp<TDbContext, TEntityIn, TEntityOut, Guid>, IBaseRepositoryWebApp<TEntityOut>
where TEntityIn : class, IDomainEntityId, IDomainEntityId<Guid>
where TEntityOut : class, IDomainEntityId, IDomainEntityId<Guid>
where TDbContext : BaseDbContext<BaseUser<Guid>>
{
protected readonly DbContext RepoDbContext;
protected readonly DbSet<TEntityIn> RepoDbSet;
protected readonly IBaseMapper<TEntityIn, TEntityOut> Mapper;
public BaseRepository(TDbContext dbContext, IBaseMapper<TEntityIn, TEntityOut> mapper)
{
RepoDbContext = dbContext;
RepoDbSet = dbContext.Set<TEntityIn>();
Mapper = mapper;
}
public virtual async Task<IEnumerable<TEntityOut>> GetAllAsync(bool noTracking = true, Guid userId = default)
{
var entities = await InitQuery(noTracking, userId).ToListAsync();
return entities.Select(e => Mapper.Map(e)!);
}
public virtual async Task<TEntityOut?> FirstOrDefaultAsync(TKey id, bool noTracking = true, Guid userId = default)
{
var query = InitQuery(noTracking, userId).FirstOrDefaultAsync(e => e.Id.Equals(id));
return Mapper.Map(await query);
}
public virtual async Task<bool> ExistsAsync(TKey id, Guid userId = default)
{
return await InitQuery(userId: userId).AnyAsync(e => e.Id.Equals(id));
}
public virtual async Task<TEntityOut?> RemoveAsync(TKey id, Guid userId = default)
{
var entity = await InitQuery(userId: userId).FirstOrDefaultAsync(e => e.Id.Equals(id));
if (entity == null) return null;
return Mapper.Map(RepoDbSet.Remove(entity).Entity);
}
public TEntityOut Add(TEntityOut? entity)
{
return Mapper.Map(RepoDbSet.Add(Mapper.Map(entity)!).Entity)!;
}
public TEntityOut Update(TEntityOut? entity)
{
return Mapper.Map(RepoDbSet.Update(Mapper.Map(entity)!).Entity)!;
}
protected virtual IQueryable<TEntityIn> InitQuery(bool noTracking = true, Guid userId = default)
{
var query = RepoDbSet.AsQueryable();
if (typeof(IDomainEntityUsers).IsAssignableFrom(typeof(TEntityIn)))
{
query = query.Where(e => (e as IDomainEntityUsers)!.UserId.Equals(userId));
}
if (noTracking)
{
query = query.AsNoTracking();
}
return query;
}
}
我的問題是,我是否忘記了某個地方,我還應該宣告使用 NoTracking 行為的地方?
uj5u.com熱心網友回復:
每次物體向下或向上移動層(例如:從 uow 到 dbcontext 再回傳,僅此處包含 2 個映射)這一事實使問題變得困難。這確保呼叫
dbContext.Entity(entity).State = EntityState.Detached;
不是一個選項,因為 Savechanges 是用 uow 物件呼叫的,而不是 dbContext。同樣在實際用例中,dbContext 是遙不可及的,因此根本無法從 dbContext 呼叫函式。
因此,我搜索了分離所有物件的選項,這些物件在 saveChanges 之后仍然附加。
ChangeTracker.Clear();
滿足了這個要求。
這個問題的解決方案是:
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = new())
{
var res = await base.SaveChangesAsync(cancellationToken);
ChangeTracker.Clear();
return res;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/343567.html
上一篇:物體框架無法插入資料
