如何使用Automapper和EF Core 2更新对象集合

时间:2018-05-25 04:07:43

标签: asp.net-core automapper ef-core-2.0

我很难弄清楚如何更新集合。

这是我的模特

    public class ProgramacionSemanal
    {
      public int ProgramacionSemanalId { get; set; }
      public int Semana { get; set; }
      public DateTime FechaInicio { get; set; }
      public DateTime FechaFin { get; set; }
      public ICollection<ProgramacionSemanalDetalle> ProgramacionSemanalDetalles { get; set; }
    }

    public class ProgramacionSemanalDetalle
    {
      [Key]
      public int ProgramacionSemanalDetalleId { get; set; }
      public int ProgramacionSemanalId { get; set; }
      [Column("ClienteId")]
      public Entidad Cliente { get; set; }
      public int UbicacionId { get; set; }
      public Ubicacion Ubicacion { get; set; }
      public int ProductoId { get; set; }
      public Producto Producto { get; set; }
      public int Lunes { get; set; }
      public int Martes { get; set; }
      public int Miercoles { get; set; }
      public int Jueves { get; set; }
      public int Viernes { get; set; }
      public int Sabado { get; set; }
      public int Domingo { get; set; }
      public AppUsuario Usuario { get; set; }
    }  

这是我的api中的一条路线。

  [HttpPut("{programacionsemanalId}")]
  public async Task<IActionResult> Put(int programacionSemanalId, [FromBody] ProgramacionSemanalViewModel model)
  {
     try
     {
        var oldProgramacionSemanal = await _repository.GetProgramacionSemanalAsync(programacionSemanalId);
        if (oldProgramacionSemanal == null) return NotFound($"No se encontro la Programación Semanal.");

        _mapper.Map(model, oldProgramacionSemanal);

        var currentUser = await _userManager.FindByNameAsync(User.Identity.Name);
        foreach (var item in oldProgramacionSemanal.ProgramacionSemanalDetalles)
        {
           var producto = await _repository.GetProductoAsync(item.ProductoId);
           if (producto == null) return BadRequest();
           item.Producto = producto;

           var ubicacion = await _repository.GetUbicacionAsync(item.UbicacionId);
           if (ubicacion == null) return BadRequest();
           item.Ubicacion = ubicacion;
           item.Usuario = currentUser;
        }

        if (await _repository.SaveAllAsync())
        {
           return Ok(_mapper.Map<ProgramacionSemanalViewModel>(oldProgramacionSemanal));
        }
     }
     catch (Exception ex)
     {
        _logger.LogError($"Threw exception while updating: {ex}");
     }

     return BadRequest("Couldn't update");
  }

我认为一切正常,

1)我收到了模型对象中定义的所有信息。

2)我从对象oldProgramacionSemanal

中获取db的所有信息

3)调用_mapper.map后,修改了对象信息oldProgramacionSemanal,将关系值设置为null,但是Cliente Pict

4)我浏览集合对象并更新关系值 enter image description here

5)当它试图保存对象时,我收到此错误

  

{System.InvalidOperationException:实体类型的实例&#39; ProgramacionSemanalDetalle&#39;无法跟踪,因为另一个具有键值的实例&#39; {ProgramacionSemanalDetalleId:38}&#39;已被跟踪。附加现有实体时,请确保仅附加具有给定键值的一个实体实例。      在Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap 1.ThrowIdentityConflict(InternalEntityEntry entry) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap 1.Add(TKey key,InternalEntityEntry entry,Boolean updateDuplicate)      在Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.StartTracking(InternalEntityEntry entry)      在Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState oldState,EntityState newState,Boolean acceptChanges)      在Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState entityState,Boolean acceptChanges,Nullable 1 forceStateWhenUnknownKey) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityGraphAttacher.PaintAction(EntityEntryGraphNode node, Boolean force) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityEntryGraphIterator.TraverseGraph[TState](EntityEntryGraphNode node, TState state, Func 3 handleNode)      在Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityGraphAttacher.AttachGraph(InternalEntityEntry rootEntry,EntityState entityState,Boolean forceStateWhenUnknownKey)      在Microsoft.EntityFrameworkCore.ChangeTracking.Internal.NavigationFixer.NavigationCollectionChanged(InternalEntityEntry条目,INAVigation导航,IEnumerable 1 added, IEnumerable 1已删除)      在Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntryNotifier.NavigationCollectionChanged(InternalEntityEntry条目,INAVigation导航,IEnumerable 1 added, IEnumerable 1已删除)      在Microsoft.EntityFrameworkCore.ChangeTracking.Internal.ChangeDetector.DetectNavigationChange(InternalEntityEntry条目,导航导航)      在Microsoft.EntityFrameworkCore.ChangeTracking.Internal.ChangeDetector.DetectChanges(InternalEntityEntry条目)      在Microsoft.EntityFrameworkCore.ChangeTracking.Internal.ChangeDetector.DetectChanges(IStateManager stateManager)      在Microsoft.EntityFrameworkCore.ChangeTracking.ChangeTracker.DetectChanges()      在Microsoft.EntityFrameworkCore.DbContext.TryDetectChanges()      在Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess,CancellationToken cancellationToken)      at C:\ gleintech \ GasApp \ GasApp.Data \ GasRepository.cs中的GasApp.Data.GasRepository.SaveAllAsync():第37行      at GasApp.Controllers.ProgramacionSemanalController.Put(Int32 programacionSemanalId,ProgramacionSemanalViewModel model)in C:\ gleintech \ GasApp \ GasApp \ Controllers \ ProgramacionSemanalController.cs:line 171}

有人能就我做错了什么给我任何建议吗?

阿尔贝托

2 个答案:

答案 0 :(得分:2)

您遇到的错误与EF Core 2.0中的问题有关 - 请参阅https://github.com/aspnet/EntityFrameworkCore/issues/7340。如果您尝试使用具有相同主键的新实体类替换实体类,则会发生这种情况。

这会在您的代码中发生,因为您更改了producto / ubicacion导航属性,告知EF更新它们。 EF通过(尝试)删除指向的现有实体并将其替换为刚刚加载的实体来实现此目的。然后,EF Core 2.0中的限制会引发您发现的错误。

我不完全确定你要做什么,因为我不知道你的存储库在做什么 - 它是否正在读取集合,是否跟踪了所有实体,你是否包括producto / ubicacion?因此,我不能给你一个确定的答案,但至少你现在知道你为什么会得到这个错误。

注意:#7340问题(我报告的)已在2.1中修复,因此这可行,但效率低,因为您删除/添加没有或几乎没有变化的关系。如果没有对producto / ubicacion进行任何更改,那么您可以考虑使用IsModified方法告诉EF他们没有更改它将保留原始数据,例如

context.Entry(entity).Navigation("PropertyName").IsModified = false;

我相信这有帮助。

答案 1 :(得分:0)

当您查询以后想要更新它的实体时,会触发此异常。例如,您在ProgramacionSemanalDetalle api中检索了标识为38的{​​{1}}实例,但在Get api中,您正在对从viewmodel映射的模型进行更改,而不是实际模型由EF跟踪。

Put