Как обновить коллекцию объектов с помощью Automapper и EF Core 2 - PullRequest
0 голосов
/ 25 мая 2018

Я с трудом пытаюсь понять, как обновить коллекцию.

Это моя модель

    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) Я получаю всю информацию из db в объекте oldProgramacionSemanal

3) После вызова _mapper.map, информация об объекте oldProgramacionSemanal изменяется, значения отношений устанавливаются в ноль, но Cliente Pict

4) Я просматриваю объекты коллекции и обновляю значение отношения enter image description here

5) При попытке сохранить объект,Я получаю эту ошибку

{System.InvalidOperationException: экземпляр типа сущности 'ProgramacionSemanalDetalle' не может быть отслежен, поскольку другой экземпляр со значением ключа '{ProgramacionSemanalDetalleId: 38}' уже отслеживается.При подключении существующих объектов убедитесь, что подключен только один экземпляр объекта с данным значением ключа.в Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap 1.ThrowIdentityConflict(InternalEntityEntry entry) at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap 1.Добавить (ключ TKey, запись InternalEntityEntry, логическое updateDuplicate) в Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.StartTracking (InternalEntityEry.EntineEntineEntworkEnt.EntityEnt.EctionCity.EntityEnt..InternalEntityEntry.SetEntityState (EntityState oldState, EntityState newState, Boolean acceptChanges) в Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState (EntityState entityState.AttachGraph (InternalEntityEntry rootEntry, EntityState entityState, логическое значение forceStateWhenUnknownKey) в Microsoft.EntityFrameworkCore.ChangeTracking.Internal.NavigationFixer.NavigationCollectionChanged (запись InternalEntityEntry.InternalIntern.travel 1)rnalEntityEntryNotifier.NavigationCollectionChanged (InternalEntityEntry вход, INavigation навигация, IEnumerable * * 1 тысячу тридцать-одна удалены) при Microsoft.EntityFrameworkCore.ChangeTracking.Internal.ChangeDetector.DetectNavigationChange (InternalEntityEntry входа, INavigation навигации) в Microsoft.EntityFrameworkCore.ChangeTracking.Internal.ChangeDetector.DetectChanges (InternalEntityEntryзапись) в Microsoft.EntityFrameworkCore.ChangeTracking.Internal.ChangeDetector.DetectChanges (IStateManager stateManager) в Microsoft.EntityFrameworkCore.ChangeTracking.ChangeTracker.DetectChanges () в Майкрософт.EntityFrameworkxtan.ChangeCeteCtraEFeCityEteCateEF_Ext_TeF_TeKTe_EcTe_TeKeTeKeTe_Te_TeKTeTeTeTeTeKTeTeTeTeTeKeTeTeTeTTTTTTTTTTTTTTTTTTTTTBTBTBTBTBBB), содержащуюся в записи Microsoft).acceptAllChangesOnSuccess, CancellationToken CancellationToken) в GasApp.Data.GasRepository.SaveAllAsync () в C: \ gleintech \ GasApp \ GasApp.Data \ GasRepository.cs: линия 37 в GasApp.Controllers.ProgramacionSeganalControlSonellShellв C: \ gleintech \ GasApp \ GasApp \ Controllers \ ProgramacionSemanalController.cs: строка 171}

Кто-нибудь может дать мне какой-либо совет, что я делаю неправильно?

Альберто

Ответы [ 2 ]

0 голосов
/ 25 мая 2018

Ошибка, которую вы получаете, связана с проблемой в 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;

Я надеюсь, что это поможет.

0 голосов
/ 25 мая 2018

Это исключение срабатывает, когда вы запрашиваете сущность, которую позже хотите обновить.Например, вы извлекли экземпляр ProgramacionSemanalDetalle с идентификатором 38 в Get api, но в Put api вы вносите изменения в модель, отображенную из viewmodel, а не в фактическую модель, отслеживаемую EF.

foreach (var item in oldProgramacionSemanal.ProgramacionSemanalDetalles)
{
    var producto = await _repository.GetProductoAsync(item.ProductoId);
    if (producto == null)
        return BadRequest();

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

    var programacionSemanalDetalles = _repository.GetProgramacionSemanalDetalles(item.ProgramacionSemanalDetalleId)
    programacionSemanalDetalles.Producto = producto;             
    programacionSemanalDetalles.Ubicacion = ubicacion;
    programacionSemanalDetalles.Usuario = currentUser;

    // if some item properties changed
    //programacionSemanalDetalles.SomeProperty = item.SomeProperty;
}
...