Użycie automappera do edycji istniejącej pozycji

Użycie automappera do edycji istniejącej pozycji
JD
  • Rejestracja: dni
  • Ostatnio: dni
0

Hej,

poniżej moje POCO

Kopiuj
public class Order
{
    public int Id { get; set; }
    
    public int CustomerId { get; set; }
    public Customer Customer { get; set; }        
    
    public int TargetCustomerId { get; set; }
    public Customer TargetCustomer { get; set; }
    
    public int AddressId { get; set; }
    public Address Address { get; set; }

    public DateTime IssueDate { get; set; } = DateTime.Now;
    public DateTime RealizationDate { get; set; }
    public DateTime DueDate { get; set; }
    public int DueDays { get; set; }    
    public OrderStatus Status { get; set; }
    public string? Comments { get; set; }

    public int UserId { get; set; }
    public User User { get; set; }

    public List<OrderPosition> Positions { get; set; }
}
Kopiuj
public class OrderPosition
{
    public int Id { get; set; }

    public int SkuId { get; set; }
    public Sku Sku { get; set; }
    
    [Column(TypeName = "decimal(11,4)")]
    public decimal quantity { get; set; }
    
    [Column(TypeName = "decimal(15,4)")]
    public decimal price { get; set; }

    [Column(TypeName = "decimal(5,2)")]
    public decimal discount { get; set; }

    public int OrderId { get; set; }
    public Order Order { get; set; }        
}

oraz DTO

Kopiuj
public class OrderRequest
{
    public int CustomerId { get; set; }
    public int TargetCustomerId { get; set; }
    public int AddressId { get; set; }
    public DateTime RealizationDate { get; set; }
    public DateTime DueDate { get; set; }
    public OrderStatus Status { get; set; }
    public string? Comments { get; set; }
    public List<OrderPositionDto> Positions { get; set; }
}

public class OrderPositionDto
{
    public int Id { get; set; }
    public string Code { get; set; }
    public string Name { get; set; }
    public string CodeName { get; set; }
    public string Uom { get; set; }
    public decimal Quantity { get; set; }
    public decimal Price { get; set; }
    public decimal Discount { get; set; }
}

Automapperem zrobiłem coś takiego

Kopiuj
CreateMap<OrderRequest, Order>();
CreateMap<OrderPositionDto, OrderPosition>()
    .ForMember(m => m.SkuId, c => c.MapFrom(c => c.Id))
    .ForMember(m => m.Id, c => c.Ignore());

mój serwis do edycji

Kopiuj
public bool EditOrder(OrderRequest orderRequest, int id)
{
    var order = _dbContext.Orders.Include(p => p.Positions).SingleOrDefault(c => c.Id == id);

    if (order is null)
        return false;

    _mapper.Map(orderRequest, order);

    _dbContext.SaveChanges();

    return true;
}

wszystko ładnie działa NO ALE: gdy wchodzę na zamówienie i zmienię np. zamawianą ilość skutkuje to usunięciem pozycji i dodaniem nowej ( nowe id ) i zmienioną ilością.
Nie wiem czy to jest OK w EF czy nie powinno tak się dziać i coś mam nie tak?

Wilktar
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 82
1

Przed SaveChanges możesz wstawic i zobaczyć co się dzieję:

Kopiuj
_dbContext.ChangeTracker.DetectChanges();
Console.WriteLine(_dbContext.ChangeTracker.DebugView.LongView);

Według mnie podczas:

Kopiuj
  var order = _dbContext.Orders.Include(p => p.Positions).SingleOrDefault(c => c.Id == id);

encja jest pobierana i śledzona podczas przez EF.

Podczas:

Kopiuj
_mapper.Map(orderRequest, order);

Order jest aktualizowany, ale OrderPosition jest usuwany i tworzony od nowa przez mappera. Dlatego EF widzi że obiekt został usunięty i dodany jeszcze raz.

heyyou
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 192
1

wydaje mi sie, ze brakuje Ci [key] na Id, przez co pewnie to jest inna instancja (musisz skonfigurowac tak, zeby changetracker wiedzial jak porownac encje)

JP
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 1065
0

Nie tyle że brakuje [Key] bo "Id" jest domyślnie mapowane na PK, ale wartość Id z DTO musi być zmapowana do Id w POCO.
Chyba też trzeba pokazać jawnie, że Positions też trzeba dodać/zaktualizować. Np. ustawiając EntityState

Ja mam takie coś. Jeśli w Modelu Id > 0 to jest update a jeśli 0 to nowy obiekt.

Kopiuj
public async Task<ConfigModel> Update(ConfigModel model)
        {
            
            var c = _mapper.Map<Config>(model);
            var db = await _dbFactory.CreateDbContextAsync();
            db.Entry(c).State = c.Id > 0 ? EntityState.Modified : EntityState.Added;
            await db.SaveChangesAsync();
            return _mapper.Map<ConfigModel>(c);
        }

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.