首页 > 解决方案 > 无法跟踪实体类型的实例,因为跟踪了具有相同键值的另一个实例

问题描述

尝试PendingUser从数据库中删除时,出现错误:

'无法跟踪实体类型'PendingUser'的实例,因为已经在跟踪另一个具有键值'{UserId:123}'的实例。附加现有实体时,请确保仅附加一个具有给定键值的实体实例。

  public async Task RemoveAsync(PendingUser pendingUser)
  {
     _context.PendingUsers.Remove(pendingUser);
     await _context.SaveChangesAsync();
  }

我该如何解决这个问题?

标签: .netentity-framework-core

解决方案


默认情况下,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);
    }
}

服务抽象
UnitOfWork


推荐阅读