Search code examples
c#automapperfluent

Automapper with many to many and IncludeMembers


Below is my Class

  public class Account
    {
       public int Id { get; set; }
       
       public string AccountNumber { get; set; } = null!;      
       ..other fields
       
       public  SubAccount1 SubAccount1 { get; set; } = null!;
       public  SubAccount2 SubAccount2 { get; set; } = null!;
      public ICollection<AccountCustomer> AccountAndCustomers { get; set; } = new List<AccountCustomer>();   ///Many to many mapping
    }
    
   public class AccountCustomer  
   {
        public int AccountId { get; set; }
        public Account Account { get; set; } = null!;

        public int CustomerId { get; set; }
        public Customer Customer { get; set; } = null!;
        ...other fields
   }
    
 public class SubAccount1
    {
       public int AccountId { get; set; }
       public  Account Account { get; set; } = null!;
       public string  Subfield1 { get; set; } = null!;
        ..other fields
    }
    
    public class SubAccount2
    {
       public int AccountId { get; set; }
       public  Account Account { get; set; } = null!;
       public string  Subfield2 { get; set; } = null!;
        ..other fields
    }
    
 
    public class SubAccount1DTO
    {
    
       public int AccountId { get; set; }   
       
       public string AccountNumber { get; set; } = null!;
  
       public string  Subfield1 { get; set; } = null!;
       
       public IReadOnlyList<CustomerDTO> Customers { get; set; } = new List<CustomerDTO>();
    }
public class CustomerDTO
    {

        public int Id { get; set; }
        public string CustomerNo { get; set; } = null!;

        public string FirstName { get; set; } = null!;
         ..other fillds

       }

public class Customer 
    {
      

       public int Id { get; set; }  
       public string? CustomerNo { get; set; } = null!;
       ....other filds
       public ICollection<AccountCustomer> AccountAndCustomers { get; set; } = new List<AccountCustomer>();

}

Auto mapper configuration based on this link Automapper many to many

CreateMap<Customer, CustomerDTO>().ReverseMap();

CreateMap<Account, SubAccount1DTO>()                          
                .IncludeMembers(s => s.SubAccount1)
                .ForMember(d => d.Customers, opt => opt.MapFrom(s => s.AccountAndCustomers))   ///After include Customers related am getting error
                 .ReverseMap()
                  .AfterMap((s, d) =>
                  {
                      foreach (var accountCustomer in d.AccountAndCustomers)
                          accountCustomer.AccountId = s.AccountId ;
                  });
                             
    CreateMap<SubAccount1, SubAccount1DTO>(MemberList.None)
                  .ForMember(dest => dest.Id, opt => opt.Ignore())
                  .ForMember(dest => dest.AccountNumber, opt => opt.Ignore())
                  .ReverseMap();

 CreateMap<Customer, AccountCustomer>()  ----i dnt no whether this to included
            .ForMember(dest => dest.CustomerId, opt => opt.MapFrom(src => src.Id))
            .ForMember(dest => dest.Customer, opt => opt.MapFrom(src => src))
            .ForMember(dest => dest.AccountId, opt => opt.Ignore())
            .ForMember(dest => dest.Account, opt => opt.Ignore())
            ;

I need to map Account to SubAccount1DTO and Reversemap. Here SubAccount1DTO has list of customersdto But when i included below line

.ForMember(d => d.Customers, opt => opt.MapFrom(s => s.AccountAndCustomers))

i am getting below error .. Please suggest

One or more errors occurred. (The following member on Application.DTOs.Accounts.SubAccount1DTO cannot be mapped: Customers Add a custom mapping expression, ignore, add a custom resolver, or modify the destination type Application.DTOs.Accounts.SubAccount1DTO. Context: Mapping to member Customers from Domain.Entities.Accounts.Account to Application.DTOs.Accounts.SubAccount1DTO


Solution

  • The following mapping

    .ForMember(d => d.Customers, opt => opt.MapFrom(s => s.AccountAndCustomers))
    

    maps source property of type ICollection<AccountCustomer> to destination property of type IReadOnlyList<CustomerDTO>.

    AutoMapper allows that, but requires you to create map for collection element types - in this specific case, AccountCustomer to CustomerDTO (in the linked post there is similar mapping from BookCategory to CategoryDto).

    Hence the minimum you need here is adding something like this to the mapper configuration:

    CreateMap<AccountCustomer, CustomerDTO>()
        .IncludeMembers(s => s.Customer);