Following the N-tier architecture, I'm currently having issues while trying to update an entity. In my Controller, if I set the properties manually, the update works perfectly, if I set the properties mapping the ViewModel into the entity it generate the exception "...cannot track multiple objects with the same key". How can I solve this?
This is my 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; }
}
This is my 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) {
}
}
This is my Service:
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();
}
And finally, This is my Controller:
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());
}