简体   繁体   English

无法跟踪实体类型 Model 的实例,因为已跟踪另一个具有相同 {'Id'} 键值的实例

[英]The instance of entity type Model cannot be tracked because another instance with the same key value for {'Id'} is already being tracked

I have a problem, when will I do update in my database, I have this exception.我有一个问题,我什么时候会更新我的数据库,我有这个例外。

The instance of entity type 'ExpenseReport' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked.无法跟踪实体类型“ExpenseReport”的实例,因为已跟踪具有相同 {'Id'} 键值的另一个实例。 When attaching existing entities, ensure that only one entity instance with a given key value is attached.附加现有实体时,请确保仅附加一个具有给定键值的实体实例。 Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values.考虑使用 'DbContextOptionsBuilder.EnableSensitiveDataLogging' 来查看冲突的键值。 tracked already已经跟踪

This is my method to do an update.这是我进行更新的方法。

      public async Task UpdateExpenseReportForm(Guid ExpenseReportId)
        {
            var totalValue =   _uow.GetReadRepository<ExpenseItem>().FindByCondition(x => x.ExpenseReportId.Equals(ExpenseReportId)).Sum(x => x.Value);

            var expenseReprot = await _uow.GetReadRepository<ExpenseReport>().FindByCondition(x => x.Id.Equals(ExpenseReportId)).FirstOrDefaultAsync().ConfigureAwait(false);
            expenseReprot.TotalValue = totalValue - expenseReprot.AdvanceValue;
            _uow.GetWriteRepository<ExpenseReport>().Update(expenseReprot);
            await _uow.CommitAsync();

        }

An important detail is that in this method _uow.GetReadRepository <ExpenseReport> () I'm already using AsNoTracking to not map it一个重要的细节是,在这个方法_uow.GetReadRepository <ExpenseReport> ()我已经使用 AsNoTracking 来不映射它

These are methods that do get and update "repository dynamic"这些是获取和更新"repository dynamic"

  public void Update(T entity)
        {
            _dbSet.Update(entity);
        }

 public IQueryable<T> FindByCondition(Expression<Func<T, bool>> expression)
        {
            return _dbSet.Where(expression).AsNoTracking();
        }

You don't need to call _dbSet.Update because as the error message indicates the entity is already being tracked from your previous query.您不需要调用_dbSet.Update因为错误消息表明实体已经从您之前的查询中被跟踪。

Try by removing the statement "AsNoTracking" from the FindByCondition method and simply call save in the "Update" method:尝试从FindByCondition方法中删除语句“AsNoTracking”,并在“Update”方法中调用 save:

public void Update(T entity)
{
    _dbContext.SaveChanges();
}

public IQueryable<T> FindByCondition(Expression<Func<T, bool>> expression)
{
    return _dbSet.Where(expression);
}

Here is a nice generic implementation of the repository pattern that you may want to reuse:这是您可能想要重用的存储库模式的一个很好的通用实现:

public class GenericRepository<TEntity> : IRepository<TEntity> where TEntity : class
{
    /// <summary>
    /// The context object for the database
    /// </summary>
    private DbContext _context;

    /// <summary>
    /// The IObjectSet that represents the current entity.
    /// </summary>
    private DbSet<TEntity> _dbSet;

    /// <summary>
    /// Initializes a new instance of the GenericRepository class
    /// </summary>
    /// <param name="context">The Entity Framework ObjectContext</param>
    public GenericRepository(DbContext context)
    {
        _context = context;
        _dbSet = _context.Set<TEntity>();
    }

    /// <summary>
    /// Gets all records as an IQueryable
    /// </summary>
    /// <returns>An IQueryable object containing the results of the query</returns>
    public IQueryable<TEntity> GetQuery()
    {
        return _dbSet;
    }

    /// <summary>
    /// Gets all records as an IQueryable and disables entity tracking
    /// </summary>
    /// <returns>An IQueryable object containing the results of the query</returns>
    public IQueryable<TEntity> AsNoTracking()
    {
        return _dbSet.AsNoTracking<TEntity>();
    }

    /// <summary>
    /// Gets all records as an IEnumerable
    /// </summary>
    /// <returns>An IEnumerable object containing the results of the query</returns>
    public IEnumerable<TEntity> GetAll()
    {
        return GetQuery().AsEnumerable();
    }

    /// <summary>
    /// Finds a record with the specified criteria
    /// </summary>
    /// <param name="predicate">Criteria to match on</param>
    /// <returns>A collection containing the results of the query</returns>
    public IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
    {
        return _dbSet.Where<TEntity>(predicate);
    }

    public Task<TEntity> FindAsync(params object[] keyValues)
    {
        return _dbSet.FindAsync(keyValues);
    }

    /// <summary>
    /// Gets a single record by the specified criteria (usually the unique identifier)
    /// </summary>
    /// <param name="predicate">Criteria to match on</param>
    /// <returns>A single record that matches the specified criteria</returns>
    public TEntity Single(Expression<Func<TEntity, bool>> predicate)
    {
        return _dbSet.Single<TEntity>(predicate);
    }

    /// <summary>
    /// The first record matching the specified criteria
    /// </summary>
    /// <param name="predicate">Criteria to match on</param>
    /// <returns>A single record containing the first record matching the specified criteria</returns>
    public TEntity First(Expression<Func<TEntity, bool>> predicate)
    {
        return _dbSet.First<TEntity>(predicate);
    }

    /// <summary>
    /// The first record matching the specified criteria or null if not found
    /// </summary>
    /// <param name="predicate">Criteria to match on</param>
    /// <returns>A single record containing the first record matching the specified criteria or a null object if nothing was found</returns>
    public TEntity FirstOrDefault(Expression<Func<TEntity, bool>> predicate)
    {
        return _dbSet.FirstOrDefault<TEntity>(predicate);
    }

    /// <summary>
    /// Deletes the specified entitiy
    /// </summary>
    /// <param name="entity">Entity to delete</param>
    /// <exception cref="ArgumentNullException"> if <paramref name="entity"/> is null</exception>
    public void Delete(TEntity entity)
    {
        if (entity == null)
        {
            throw new ArgumentNullException("entity");
        }
        _dbSet.Remove(entity);
    }

    /// <summary>
    /// Adds the specified entity
    /// </summary>
    /// <param name="entity">Entity to add</param>
    /// <exception cref="ArgumentNullException"> if <paramref name="entity"/> is null</exception>
    public void Add(TEntity entity)
    {
        if (entity == null)
        {
            throw new ArgumentNullException("entity");
        }
        _dbSet.Add(entity);
    }


    /// <summary>
    /// Attaches the specified entity
    /// </summary>
    /// <param name="entity">Entity to attach</param>
    public void Attach(TEntity entity)
    {
        _dbSet.Attach(entity);
    }

    /// <summary>
    /// Detaches the specified entity
    /// </summary>
    /// <param name="entity">Entity to attach</param>
    public void Detach(TEntity entity)
    {
        _context.Entry(entity).State = EntityState.Detached;
    }

    public void MarkModified(TEntity entity)
    {
        _context.Entry(entity).State = EntityState.Modified;
    }

    public DbEntityEntry<TEntity> GetEntry(TEntity entity)
    {
        return _context.Entry(entity);
    }

    /// <summary>
    /// Saves all context changes
    /// </summary>
    public void SaveChanges()
    {
        _context.SaveChanges();
    }

    /// <summary>
    /// Releases all resources used by the WarrantManagement.DataExtract.Dal.ReportDataBase
    /// </summary>
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    /// <summary>
    /// Releases all resources used by the WarrantManagement.DataExtract.Dal.ReportDataBase
    /// </summary>
    /// <param name="disposing">A boolean value indicating whether or not to dispose managed resources</param>
    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (_context != null)
            {

                _context.Dispose();

                _context = null;

            }
        }
    }
}

Here is the interface:这是界面:

public interface IRepository<TEntity> : IDisposable where TEntity : class
{
    IQueryable<TEntity> GetQuery();
    IEnumerable<TEntity> GetAll();
    IQueryable<TEntity> AsNoTracking();
    IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate);
    TEntity Single(Expression<Func<TEntity, bool>> predicate);
    TEntity First(Expression<Func<TEntity, bool>> predicate);
    TEntity FirstOrDefault(Expression<Func<TEntity, bool>> predicate);
    void Add(TEntity entity);
    void Delete(TEntity entity);
    void Attach(TEntity entity);
    void Detach(TEntity entity);
    void MarkModified(TEntity entity);
    void SaveChanges();
}

Note that you only need to call "Attach" or "MarkModified" if the entity is not being tracked, in most scenarios you can simply make a query, modify some properties of a tracked entity and then call SaveChanges .请注意,如果实体未被跟踪,您只需要调用“Attach”或“MarkModified”,在大多数情况下,您可以简单地进行查询,修改被跟踪实体的某些属性,然后调用SaveChanges

You can also combine the repositories with a unit of work so you can have more control over transactions, etc... here is an example:您还可以将存储库与一个工作单元相结合,以便您可以更好地控制事务等……这是一个示例:

public class UnitOfWork : IUnitOfWork
{
    private readonly YouDatabaseContext _context = new YouDatabaseContext();
    private DbContextTransaction _dbContextTransaction;
    private GenericRepository<ExpenseReport> _expenseReportRepository;
    private GenericRepository<ExpenseItem> _expenseItemRepository;

    public GenericRepository<ExpenseReport> ExpenseReportRepository
    {
        get
        {
            if (_expenseReportRepository == null)
            {
                _expenseReportRepository = new GenericRepository<ExpenseReport>(_context);
            }
            return _expenseReportRepository;
        }

        set
        {
            _expenseReportRepository = value;
        }
    }
    
    public GenericRepository<ExpenseItem> ExpenseItemRepository
    {
        get
        {
            if (_expenseItemRepository == null)
            {
                _expenseItemRepository = new GenericRepository<ExpenseItem>(_context);
            }
            return _expenseItemRepository;
        }

        set
        {
            _expenseItemRepository = value;
        }
    }

    public void BeginTransaction()
    {
        _dbContextTransaction = _context.Database.BeginTransaction();
    }

    public void BeginTransaction(IsolationLevel isolationLevel)
    {
        _dbContextTransaction = _context.Database.BeginTransaction(isolationLevel);
    }

    public int Save()
    {
        return _context.SaveChanges();
    }

    public Task<int> SaveAsync()
    {
        return _context.SaveChangesAsync();
    }

    public void Commit()
    {
        if (_dbContextTransaction!=null)
        {
            _dbContextTransaction.Commit();
        }
    }

    public void RollBack()
    {
        if (_dbContextTransaction != null)
        {
            _dbContextTransaction.Rollback();
        }
    }

    private bool _disposed;

    protected virtual void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            if (disposing)
            {
                _context.Dispose();
                _dbContextTransaction?.Dispose();
            }
        }
        _disposed = true;
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

And the interface:和界面:

public interface IUnitOfWork : IDisposable
{
    void BeginTransaction();
    void BeginTransaction(IsolationLevel isolationLevel);
    int Save();
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 无法跟踪实体类型“Item”的实例,因为已跟踪另一个具有与 {'Id'} 相同键值的实例 - The instance of entity type 'Item' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked 无法跟踪实体类型“书签”的实例,因为已经在跟踪具有相同键值 {'ID'} 的另一个实例 - The instance of entity type 'Bookmark' cannot be tracked because another instance with the same key value for {'ID'} is already being tracked 实体类型的实例 <T> 无法跟踪,因为已经跟踪了另一个具有相同的{&#39;Id&#39;}键值的实例 - The instance of entity type <T> cannot be tracked because another instance with the same key value for {'Id'} is already being tracked 无法跟踪实体类型“Bus”的实例,因为已经在跟踪具有相同键值 {'Id'} 的另一个实例 - The instance of entity type ‘Bus’ cannot be tracked because another instance with the same key value for {‘Id’} is already being tracked 无法跟踪实体类型“AppUser”的实例,因为已跟踪另一个具有与 {'Id'} 相同键值的实例 - The instance of entity type 'AppUser' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked 无法跟踪实体类型“ Article”的实例,因为已经跟踪了另一个具有相同键值的{&#39;Id&#39;}实例 - The instance of entity type 'Article' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked 无法跟踪实体类型“用户”的实例,因为已经在跟踪另一个具有相同键值的“Id”实例 - The instance of entity type 'User' cannot be tracked because another instance with the same key value for 'Id' is already being tracked 错误:无法跟踪实体类型“X”的实例,因为已在跟踪另一个具有键值“{ID:3}”的实例 - Error: The instance of entity type 'X' cannot be tracked because another instance with the key value '{ID: 3}' is already being tracked 无法跟踪实体类型“配置文件”的实例,因为已在跟踪另一个具有键值“{Id: 1087}”的实例 - The instance of entity type 'Profile' cannot be tracked because another instance with the key value '{Id: 1087}' is already being tracked 无法跟踪实体类型“ Customer”的实例,因为已经跟踪了另一个键值为“ {Id:…}”的实例 - The instance of entity type 'Customer' cannot be tracked because another instance with the key value '{Id: …}' is already being tracked
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM