skip to Main Content

I have the following two ShopifySharp objects.

public class Product
{            
    public string Title { get; set; }

    public string BodyHtml { get; set; }

    public IEnumerable<ProductVariant> Variants { get; set; }
}


public class ProductVariant 
{
    public string Title { get; set; }

    public string Barcode { get; set; }

}

I then have the following model

public class ShopifyVariant 
{
    public long Id { get; set; }

    public long ProductId { get; set; }

    public string ProductName { get; set; }

    public string VariantName { get; set; }

    public string Price { get; set; }
}

I want to map an instance of ShopifySharp.Product to IEnumerable<ShopifyVariant> because each ShopifySharp.Product will always have have AT LEAST a single ProductVariant.

Usually this would be a trivial problem because you could simply create a map between the two objects along the lines of:

this.CreateMap<ShopifySharp.ProductVariant, ShopifyVariant>()

BUT I need to get the ProductName and ProductId for each variant which can only be obtained from the ShopifySharp.Product object.

My initial thought was to try something like this

this.CreateMap<ShopifySharp.ProductVariant, ShopifyVariant>()
.ForMember(o => o.Id, o => o.MapFrom(f => f.Id))
.ForMember(o => o.ProductId, o => o.MapFrom((src, dest, m, c) => c.Items["ProductId"]))
.ForMember(o => o.ProductName, o => o.MapFrom((src, dest, m, c) => c.Items["ProductName"]))
.ForMember(o => o.VariantName, o => o.MapFrom(f => f.Title));

this.CreateMap<ShopifySharp.Product, IEnumerable<ShopifyVariant>>()

But it was unclear to me how to actually create the projection from Product to IEnumerable.

I’m currently playing with using a Custom ITypeConverter but haven’t worked it out yet.

Can anyone help? How do you map a single instance of an object to a collection of reduced entities?

2

Answers


  1. Chosen as BEST ANSWER

    I have solved the problem (suboptimally) using the following mappings.

    this.CreateMap<ShopifySharp.ProductVariant, ShopifyVariant>().ForMember(o => o.Id, o => o.MapFrom(f => f.Id))
    .ForMember(o => o.ProductId, o => o.MapFrom(f => f.ProductId))
    .ForMember(o => o.VariantName, o => o.MapFrom(f => f.Title))
    .ForMember(o => o.Barcode, o => o.MapFrom(f => f.Barcode))
    .ForMember(o => o.Price, o => o.MapFrom(f => f.Price))
    .ForMember(o => o.Grams, o => o.MapFrom(f => f.Grams))
    .ForMember(o => o.Taxable, o => o.MapFrom(f => f.Taxable))
    .ForMember(o => o.Weight, o => o.MapFrom(f => f.Weight))
    .ForMember(o => o.WeightUnit, o => o.MapFrom(f => f.WeightUnit))
    .ForMember(o => o.SKU, o => o.MapFrom(f => f.SKU));
    
    this.CreateMap<ShopifySharp.Product, ShopifyVariant>().ForMember(o => o.ProductName, o => o.MapFrom(f => f.Title));
    
    this.CreateMap<IEnumerable<ShopifySharp.Product>, IEnumerable<ShopifyVariant>>()
    .ConvertUsing<ShopifyProductsToVariantsCollectionTypeConverter>();
    
    internal class ShopifyProductsToVariantsCollectionTypeConverter : ITypeConverter<IEnumerable<ShopifySharp.Product>, IEnumerable<ShopifyVariant>>
    {
        public IEnumerable<ShopifyVariant> Convert(IEnumerable<ShopifySharp.Product> source, IEnumerable<ShopifyVariant> destination, ResolutionContext context)
        {
            var result = new List<ShopifyVariant>();
            foreach (var product in source)
            {
                foreach (var variant in product.Variants)
                {
                    var mappedVariant = context.Mapper.Map<ShopifyVariant>(variant);
                    context.Mapper.Map(product, mappedVariant);
                    result.Add(mappedVariant);
                }
            }
    
            return result;
        }
    }
    

    Would love to see a better approach.


  2. As I’ve already said in the comments, some LINQ would help a lot here. But here it is. You can apply the same idea to your version. Most of the MapFroms you have are useless.

    c.CreateMap<ProductVariant, ShopifyVariant>()
        .ForMember(o => o.ProductId, o => o.MapFrom((src, dest, m, context) => context.Items["ProductId"]))
        .ForMember(o => o.ProductName, o => o.MapFrom((src, dest, m, context) => context.Items["ProductName"]))
        .ForMember(o => o.VariantName, o => o.MapFrom(f => f.Title));
    c.CreateMap<Product, IEnumerable<ShopifyVariant>>().ConvertUsing((product,variant,context)=>
    {
        context.Items["ProductId"] = product.Id;
        context.Items["ProductName"] = product.Name;
        return context.Mapper.Map<List<ShopifyVariant>>(product.Variants);
    });
    
    new []{new Product{Id=1,Variants=new[]{new ProductVariant{Id=1},new ProductVariant{Id=2}}}, new Product{Id=2,Variants=new[]{new ProductVariant{Id=3},new ProductVariant{Id=4}}}}
    .SelectMany(product=>mapper.Map<List<ShopifyVariant>>(product,_=>{}));
    

    The IEnumerable map can be omitted and replaced with the same code inline, when calling Map.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search