簡體   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

我有一個問題,我什么時候會更新我的數據庫,我有這個例外。

無法跟蹤實體類型“ExpenseReport”的實例,因為已跟蹤具有相同 {'Id'} 鍵值的另一個實例。 附加現有實體時,請確保僅附加一個具有給定鍵值的實體實例。 考慮使用 'DbContextOptionsBuilder.EnableSensitiveDataLogging' 來查看沖突的鍵值。 已經跟蹤

這是我進行更新的方法。

      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();

        }

一個重要的細節是,在這個方法_uow.GetReadRepository <ExpenseReport> ()我已經使用 AsNoTracking 來不映射它

這些是獲取和更新"repository dynamic"

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

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

您不需要調用_dbSet.Update因為錯誤消息表明實體已經從您之前的查詢中被跟蹤。

嘗試從FindByCondition方法中刪除語句“AsNoTracking”,並在“Update”方法中調用 save:

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

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

這是您可能想要重用的存儲庫模式的一個很好的通用實現:

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;

            }
        }
    }
}

這是界面:

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();
}

請注意,如果實體未被跟蹤,您只需要調用“Attach”或“MarkModified”,在大多數情況下,您可以簡單地進行查詢,修改被跟蹤實體的某些屬性,然后調用SaveChanges

您還可以將存儲庫與一個工作單元相結合,以便您可以更好地控制事務等……這是一個示例:

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);
    }
}

和界面:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM