Обновление EFCore с использованием репозитория UnitOfWork и сервиса с AutoMapper - PullRequest
0 голосов
/ 08 июня 2018

В соответствии с N-уровневой архитектурой, в настоящее время у меня возникают проблемы при попытке обновить сущность.В моем контроллере, если я устанавливаю свойства вручную, обновление работает отлично, если я устанавливаю свойства, отображающие 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; }

}

Это мой общий репозиторий + 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 голосов
/ 08 июня 2018

Это не работает в вашем случае, потому что вы используете перегрузку IMapper.Map, которая создает новый экземпляр объекта currency.Из-за того, что ваша GetCurrencyById отслеживает вашу сущность после успешной выборки, вы получите исключение, поскольку вам придется создавать экземпляры с тем же ключом (один отслеживается уже в DbContext, а новый - созданный картографом).

Есть две вещи, которые вы можете сделать, чтобы предотвратить это:

  1. Использовать метод AsNoTracking() при извлечении из базы данных
  2. Использовать перегрузку IMapper.Map, котораяпринимает как целевые, так и исходные экземпляры currency:

    _mapper.Map (currency, currencyToUpdate);

...