C# 使用UnitOfWork存储库和带有AutoMapper的服务进行EFCore更新

C# 使用UnitOfWork存储库和带有AutoMapper的服务进行EFCore更新,c#,model-view-controller,entity-framework-core,ef-core-2.0,C#,Model View Controller,Entity Framework Core,Ef Core 2.0,遵循N层体系结构,我当前在尝试更新实体时遇到问题。在我的控制器中,如果我手动设置属性,则更新工作正常,如果我设置将ViewModel映射到实体的属性,则会生成异常“…无法使用同一关键点跟踪多个对象”。 我怎样才能解决这个问题 这是我的工作单元: public class UnitOfWork : IUnitOfWork { private readonly CoreContext _context; private IGenericRepository<Currency&g

遵循N层体系结构,我当前在尝试更新实体时遇到问题。在我的控制器中,如果我手动设置属性,则更新工作正常,如果我设置将ViewModel映射到实体的属性,则会生成异常“…无法使用同一关键点跟踪多个对象”。 我怎样才能解决这个问题

这是我的工作单元:

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

}
最后,这是我的控制器:

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());
    }
公共类CurrencyController:控制器
{
专用只读ICurrencyService\u currencyService;
专用只读IMapper\u映射器;
公共货币控制器(ICurrencyService货币服务,IMapper映射器)
:base()
{
_currencyService=currencyService;
_映射器=映射器;
}
[HttpPost]
public ActionResult UpdateCurrent([DataSourceRequest]DataSourceRequest dsRequest,CurrencyViewModel货币)
{
if(currency!=null&&ModelState.IsValid)
{
var currencyToUpdate=\u currencyService.GetCurrencyById(currency.CurrencyId);
if(currencyToUpdate!=null)
{
//更新不工作
//currencyToUpdate=\u mapper.Map(货币);
//更新工作
currencyToUpdate.Description=currency.Description;
currencyToUpdate.Code=currency.Code;
currencyToUpdate.Symbol=currency.Symbol;
_currencyService.UpdateCurrency(currencyToUpdate);
_currencyService.SaveChanges();
}
}
返回Json(ModelState.ToDataSourceResult());
}

它在您的情况下不起作用,因为您使用的是
IMapper.Map
重载,它创建了
currency
对象的新实例。由于
GetCurrencyById
在成功获取后跟踪实体,您将遇到异常,因为您必须使用相同的键创建实例(一个已经在DbContext中跟踪,另一个是mapper创建的新的)

有两件事可以防止它:

  • 从数据库获取数据时使用
    AsNoTracking()
    方法
  • 使用
    IMapper.Map
    重载,该重载同时获取
    currency
    的目标和源实例:

    _mapper.Map(货币、货币更新)

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