.net - 无法跟踪实体类型的实例,因为跟踪了具有相同键值的另一个实例
问题描述
尝试PendingUser
从数据库中删除时,出现错误:
'无法跟踪实体类型'PendingUser'的实例,因为已经在跟踪另一个具有键值'{UserId:123}'的实例。附加现有实体时,请确保仅附加一个具有给定键值的实体实例。
public async Task RemoveAsync(PendingUser pendingUser)
{
_context.PendingUsers.Remove(pendingUser);
await _context.SaveChangesAsync();
}
我该如何解决这个问题?
解决方案
默认情况下,DBContext 被注入为scoped
. 这种做法有助于保持跟踪尽可能干净。
但是,这可能是一个简单的跟踪问题。
如果pendingUser
是输入(如 DTO)并且没有从上下文中恢复(带跟踪),则需要在删除之前附加它。
贝娄,一些建议可以用作删除行为:
public abstract class Repository<TEntity, TId> : IRepository<TEntity, TId>
where TEntity : Entity<TId>
where TId : struct
{
private readonly DbSet<TEntity> _dbSet;
protected Repository(DbContext dbDbContext)
{
_dbSet = dbDbContext.Set<TEntity>();
}
public virtual void Delete(TId id)
{
var entity = GetById(id, asTracking: true);
if (entity is null) return;
_dbSet.Remove(entity);
}
public virtual void Delete(TEntity entity)
{
if (entity is null) return;
_dbSet.Attach(entity);
_dbSet.Remove(entity);
}
public virtual async Task DeleteAsync(TId id, CancellationToken cancellationToken)
{
var entity = await GetByIdAsync(id, cancellationToken, asTracking: true);
if (entity is null) return;
_dbSet.Remove(entity);
}
public virtual async Task DeleteAsync(TEntity entity, CancellationToken cancellationToken)
{
if (entity is null) return;
await Task.Run(() => Delete(entity), cancellationToken);
}
}
在这种特殊情况下,SaveChanges
和其他DBContext
行为由UnitOfWork
. 这提供了服务层的事务控制。
public abstract class Service<TEntity, TModel, TId> : IService<TEntity, TModel, TId>
where TEntity : Entity<TId>
where TModel : Model<TId>
where TId : struct
{
protected readonly IMapper Mapper;
protected readonly IRepository<TEntity, TId> Repository;
protected readonly IUnitOfWork UnitOfWork;
protected Service(IRepository<TEntity, TId> repository, IUnitOfWork unitOfWork, IMapper mapper)
{
Repository = repository;
UnitOfWork = unitOfWork;
Mapper = mapper;
}
public virtual bool Delete(TId id)
{
if (IsValid(id) is false) return default;
Repository.Delete(id);
return UnitOfWork.SaveChanges();
}
public virtual bool Delete(TModel model)
{
if (IsValid(model) is false) return default;
var entity = Mapper.Map<TEntity>(model);
return OnDelete(entity);
}
public virtual async Task<bool> DeleteAsync(TId id, CancellationToken cancellationToken)
{
if (IsValid(id) is false) return default;
await Repository.DeleteAsync(id, cancellationToken);
return await UnitOfWork.SaveChangesAsync(cancellationToken);
}
public virtual async Task<bool> DeleteAsync(TModel model, CancellationToken cancellationToken)
{
if (IsValid(model) is false) return default;
var entity = Mapper.Map<TEntity>(model);
return await OnDeleteAsync(entity, cancellationToken);
}
}
推荐阅读
- linux - 使用 hcitool 发送 HCI ACL 数据包
- c# - 无法比较数组中的两个元素。至少一个对象必须实现 IComparable
- javascript - 使用闭包来净化一个通过递归构建对象的函数——JavaScript
- vb.net - DataTable.ImportRow() 方法的 VB 问题
- python - FileStorage 文件在病毒扫描后似乎是空的
- android - 导航抽屉不显示任何项目
- python - How to treeify Python dicts?
- hive - 为什么 tez 上的 hive 有时运行速度是原来的两倍?
- c# - 为什么当我添加参考时它不允许我在名称空间中添加歌曲
- azure - 从表存储(性能计数器等)中删除旧的 Windows Azure 诊断数据