使用AutoOper使用UnitOfWork存储库和服务进行EFCore更新

时间:2018-06-08 07:02:13

标签: c# model-view-controller entity-framework-core ef-core-2.0

遵循N层架构,我在尝试更新实体时遇到了问题。在我的Controller中,如果我手动设置属性,则更新工作正常,如果我设置将ViewModel映射到实体的属性,则会生成异常" ...无法使用相同的键跟踪多个对象"。 我该如何解决这个问题?

这是我的UnitOfWork:

public class UnitOfWork : IUnitOfWork
{
    private readonly CoreContext _context;
    private IGenericRepository<Currency> currencyRepository;

    private static string DataConnectionString => new DatabaseConfiguration().GetDataConnectionString();

    public UnitOfWork(CoreContext context)
    {
        var optionsBuilder = new DbContextOptionsBuilder<CoreContext>();
        optionsBuilder.UseSqlServer(DataConnectionString);
        _context = new CoreContext(optionsBuilder.Options);

    }

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

    public async Task CommitAsync()
    {
        await _context.SaveChangesAsync();
    }

    private bool disposed = false;

    protected virtual void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
            if (disposing)
            {
                _context.Dispose();
            }
        }
        this.disposed = true;
    }

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


    public IGenericRepository<Currency> CurrencyRepository
    {
        get { return this.currencyRepository ?? (this.currencyRepository = new GenericRepository<Currency>(_context)); }
    }

}


public interface IUnitOfWork : IDisposable
{
    int Commit();
    Task CommitAsync();
    IGenericRepository<Currency> CurrencyRepository { get; }

}

这是我的Generic Repository + CurrencyRepository:

public class GenericRepository<T> : IGenericRepository<T> where T : class
{
    internal CoreContext _context;
    internal DbSet<T> _entities;

    public GenericRepository(CoreContext context)
    {
        _context = context;
        _entities = context.Set<T>();
    }

    public virtual void Update(T entityToUpdate)
    {
        _context.Entry(entityToUpdate).State = EntityState.Modified;
    }

    public IEnumerable<T> GetBy(Expression<Func<T, bool>> predicate)
    {
        IEnumerable<T> query = _entities.Where(predicate).AsEnumerable();
        return query;
    }

}


public interface IGenericRepository<T> where T : class
{
    void Update(T entity);
    IEnumerable<T> GetBy(Expression<Func<T, bool>> predicate);

}

public class CurrencyRepository : GenericRepository<Currency>, ICurrencyRepository
{        
    public CurrencyRepository(CoreContext context)
    : base(context) {
    }
}

这是我的服务:

public class CurrencyService : ICurrencyService
{
    private readonly IUnitOfWork _unitOfWork;

    public void UpdateCurrency(Currency currency)
    {
        _unitOfWork.CurrencyRepository.Update(currency);
    }

    public Currency GetCurrencyById(int Id)
    {
        return _unitOfWork.CurrencyRepository.GetBy(x => x.CurrencyId == Id).Single();

    }

    public int SaveChanges()
    {
        return _unitOfWork.Commit();
    }

}

public interface ICurrencyService 
{
    Currency GetCurrencyById(int Id);
    void UpdateCurrency(Currency currency);

    int SaveChanges();
}

最后,这是我的控制器:

public class CurrencyController : Controller
{
    private readonly ICurrencyService _currencyService;
    private readonly IMapper _mapper;

    public CurrencyController(ICurrencyService currencyService, IMapper mapper)
        : base()
    {
        _currencyService = currencyService;
        _mapper = mapper;
    }


    [HttpPost]
    public ActionResult UpdateCurrency([DataSourceRequest] DataSourceRequest dsRequest, CurrencyViewModel currency)
    {
        if (currency != null && ModelState.IsValid)
        {
            var currencyToUpdate = _currencyService.GetCurrencyById(currency.CurrencyId);

            if (currencyToUpdate != null)
            {
                //UPDATE NOT WORKING
                //currencyToUpdate = _mapper.Map<CurrencyViewModel, Currency>(currency);

                //UPDATE WORKING
                currencyToUpdate.Description = currency.Description;
                currencyToUpdate.Code= currency.Code;
                currencyToUpdate.Symbol = currency.Symbol;

                _currencyService.UpdateCurrency(currencyToUpdate);
                _currencyService.SaveChanges();
            }
        }

        return Json(ModelState.ToDataSourceResult());
    }

1 个答案:

答案 0 :(得分:1)

它在您的情况下不起作用,因为您正在使用IMapper.Map重载,它会创建currency对象的新实例。由于您的GetCurrencyById在成功获取后跟踪您的实体这一事实,您将最终得到异常,因为您将需要具有相同密钥的实例(一个已在DbContext中跟踪,另一个已创建映射器) )。

你可以做两件事来阻止它:

  1. 从数据库中提取时使用AsNoTracking()方法
  2. 使用IMapper.Map重载,它包含currency的目标和源实例:

    _mapper.Map(currency,currencyToUpdate);