Модель карты с коллекцией внутри

#c# #entity-framework-core #automapper

#c# #сущность-фреймворк-ядро #automapper

Вопрос:

У меня есть конечная точка API примерно так:

         [HttpGet("{shoppingCartId}")]
        public async Task<IActionResult> GetShoppingCart(int shoppingCartId)
        {
            var shoppingCart = await context.ShoppingCarts.Include(c => c.ShoppingCartItems).SingleOrDefaultAsync(c => c.Id == shoppingCartId);

            if (shoppingCart == null)
                return NotFound("There is no shoppingCart for specified query.");

            return Ok(shoppingCart);
        }
  

Это работает нормально. Возвращает ShoppingCart с ShoppingCartItems, как и ожидалось.

Но я не хочу возвращать ShoppingCart, а shoppingCartResource. Что-то вроде этого:

         [HttpGet("{shoppingCartId}")]
        public async Task<IActionResult> GetShoppingCart(int shoppingCartId)
        {
            var shoppingCart = await context.ShoppingCarts.Include(c => c.ShoppingCartItems).SingleOrDefaultAsync(c => c.Id == shoppingCartId);

        if (shoppingCart == null)
            return NotFound("There is no shoppingCart for specified query.");

        var shoppingCartResource = mapper.Map<ShoppingCart, ShoppingCartResource>(shoppingCart);
        return Ok(shoppingCartResource);
    }
  

Как вы можете видеть, модель ShoppingCart содержит коллекцию ShoppingCartItem внутри.

     public class ShoppingCart
    {
        public int Id { get; set; }
        public DateTime DateCreated { get; set; }
        public ICollection<ShoppingCartItem> ShoppingCartItems { get; set; }

        public ShoppingCart()
        {
            ShoppingCartItems = new Collection<ShoppingCartItem>();
        }
    }
  

И вот модель ShoppingCartResource

   public class ShoppingCartResource
    {
        public int Id { get; set; }
        public DateTime DateCreated { get; set; }
        public ICollection<ShoppingCartItemResource> ShoppingCartItemResources { get; set; }

        public ShoppingCartResource()
        {
            ShoppingCartItemResources = new Collection<ShoppingCartItemResource>();
        }
    }
  

Код отображения является:

  CreateMap<ShoppingCart, ShoppingCartResource>();
 CreateMap<ShoppingCartItem, ShoppingCartItemResource>();
  

Ошибки нет, но я получил единственный shoppingCartResource с пустым ShoppingCartItemResource.

Ответ №1:

Вам не хватает одной строки, указывающей AutoMapper, где из нее следует отображать ShoppingCartItemResources , потому что соответствующее свойство в исходном объекте не имеет того же имени — ShoppingCartItems , поэтому оно не будет работать автоматически. Просто добавьте это:

 CreateMap<ShoppingCart, ShoppingCartResource>()
    .ForMember(
        dst => dst.ShoppingCartItemResources, 
        opts => opts.MapFrom(src => src.ShoppingCartItems));
CreateMap<ShoppingCartItem, ShoppingCartItemResource>();
  

Ответ №2:

По умолчанию AutoMapper следует соглашению об именовании, которое автоматически создает карту между исходным свойством и целевым свойством, если их имена совпадают, и вам не нужно ничего настраивать для этого. Но, если вам нужна карта между двумя свойствами и их имена не совпадают, тогда вам нужно явно определить конфигурацию для этой карты.

Оба ваших объекта ShoppingCartResource и ShoppingCart имеют свойства с именами Id и DateCreated , и поэтому они были сопоставлены автоматически.

Чтобы получить карту между вашими ICollection свойствами —

  1. если вы хотите автоматическую карту, вы должны дать им соответствующее имя
  2. если вы хотите сохранить различие в именовании, вы должны явно определить конфигурацию для их сопоставления. Что-то вроде —
 CreateMap<ShoppingCart, ShoppingCartResource>()
    .ForMember(d => d.ShoppingCartItemResources, opt => opt.MapFrom(s => s.ShoppingCartItems));

CreateMap<ShoppingCartItem, ShoppingCartItemResource>();