How to map a class with dynamically generated class in Automapper

2,262 views
Skip to first unread message

pankaj kaushik

unread,
Mar 26, 2019, 1:37:48 AM3/26/19
to AutoMapper-users
I have a view model which has a collection called CustomFields as following:

 public class CustomerGridViewModel
    {
        /* Customer Id */
 
       public int CustomerId { get; set; }

        public string CustomerNumber { get; set; }
        
        public IEnumerable<CustomFieldValue> CustomFieldValues { get; set; }
}


public class CustomFieldValue 
    {
    
            public string Name { get; set; }
            public string Value { get; set; }
        
    }

I have generated new dynamic class which can hold customer and its custom fields as properties instead of collections like:

 public class NewCustomerViewModel
    {
    
       public int CustomerId { get; set; }

        public string CustomerNumber { get; set; }
        
        public string field1 {get;set;}
        
        public int field2 {get;set;}
}


Now I want to map this dynamic class with CustomerGridViewModel so that all the properties and customfields can be mapped with this newly generated dynamic class.

Can any one please help me on this?


Jimmy Bogard

unread,
Mar 26, 2019, 8:53:33 AM3/26/19
to automapper-users
How is this class dynamically generated?

--
You received this message because you are subscribed to the Google Groups "AutoMapper-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to automapper-use...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

pankaj kaushik

unread,
Mar 26, 2019, 8:56:35 AM3/26/19
to AutoMapper-users
This class is generated using TypeBuilder and by passing required properties and types of properties

Jimmy Bogard

unread,
Mar 26, 2019, 9:13:25 AM3/26/19
to automapper-users
Ah, so Reflection.Emit. Yikes!


That creates maps on the fly (though I'm very hesitant to use that except in special circumstances)

pankaj kaushik

unread,
Mar 27, 2019, 2:28:58 AM3/27/19
to AutoMapper-users
Hi Jimmy,

Really appreciating your replies and thanks for that.

Yeah I am using reflection.

Also I checked the link you provided but the problem is that source is type of IQueryable<CustomerGridViewModel> and the destination type is dynamic object.
So I am confused how can I use type of destination while mapping. I am trying it in following ways but that doesn't work:

 MappingProfile mp = new MappingProfile();

            foreach (var prop in CustomFieldGridColumnSettings?.Select(cs => cs.PropertyName))
            {               
                // with Iqueryable
                mp.CreateMap<CustomerGridViewModel, object>().ForMember(prop, opt => opt.MapFrom(
           src => (src.CustomFieldValues.FirstOrDefault(f => f.Name == prop).Value)));

                mp.CreateMap<ICustomFieldViewModel, object>().ForMember("CustomFieldValues", opt => opt.Ignore());
            }

            var config = new MapperConfiguration(cfg => cfg.AddProfile(mp));
            var mapper = config.CreateMapper();

            // With IQueryable
            var dataQueryable = listOfCustomers.ProjectTo<object>(mapper.ConfigurationProvider);

In above code CustomFieldGridColumnSettings is the collection of custom fields containing name and values. So I am creating map for all dynamic fields for iqueryable. But when I try ProjectTo then it doesn't work

Jimmy Bogard

unread,
Mar 27, 2019, 10:36:01 AM3/27/19
to automapper-users
OK this is getting more complicated then. Is this for like OData or similar?

pankaj kaushik

unread,
Mar 29, 2019, 2:23:44 AM3/29/19
to AutoMapper-users
This is for IQueryable data which is coming from Sql database.

Also I have created following code but I am stuck on just mapping of dynamic fields. Can you please check how can I map fields from dictionary to the object and then project to that object to new object.
I am able to project to the new object along with custom fields but I am not able to map values for custom fields which are in the collection of source object.

 var baseType = typeof(CustomerGridViewModel);

                var assembly = new AssemblyName("SedonaOneDynamicAssembly");

                var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assembly, AssemblyBuilderAccess.Run);

                var moduleBuilder = assemblyBuilder.DefineDynamicModule("SedonaOneTransientModule");

                var typeBuilder = moduleBuilder.DefineType(
                    "CustomerGridPlusViewModel",
                    TypeAttributes.Public
                    | TypeAttributes.Class
                    | TypeAttributes.AutoClass
                    | TypeAttributes.AnsiClass,
                    baseType
                    );

                var fields = DealerCustomFieldServiceDI.GetDealerCustomFieldsByEntityId(EntityEnum.Customer.ToInt32(), false);

                var toMap = new Dictionary<string, string>();

                foreach (var field in fields)
                {
                    Type fieldType = typeof(string);

                    var propName = $"_CUSTOM_{field.Name}";

                    var fieldBuffer = typeBuilder.DefineField(propName, fieldType, FieldAttributes.Public);

                    toMap.Add(propName, field.Name);
                }

                var t = typeBuilder.CreateType();

                var stuff = DealerCustomersServiceDI.GetCustomersForGrid(isMasterCustomer, isProspect, isInactive);

                var mapperConfig = new MapperConfiguration(cfg =>
                {
                    var customerType = typeof(aCustomer);

                    cfg.AddProfile<MappingProfile>();

                    var map = cfg.CreateMap(baseType, t);                  
                    ;
                   
                    foreach (var x in toMap)
                    {
                        map.ForMember(x.Key, opt => opt.MapFrom("CustomFieldValues")); // this is the part I need to solve 
                     }
// this "CustomFieldValues" is collection in source object(basetype) which contains following structure:
/*
 //public class CustomFieldValue 
 //   {
    
  //          public string Name { get; set; }
  //          public string Value { get; set; }
 //       
//    }
I need to map field name as present in dictionary with the value of same field present in this collection
*/
                        
           
                });

                
                var mapper = mapperConfig.CreateMapper();

                var methodInfo = mapper.GetType()
                    .GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic)
                    .Where(x => x.Name.EndsWith("ProjectTo"))
                    .FirstOrDefault();
                var genericMethodInfo = methodInfo.MakeGenericMethod(t);

                var eType = typeof(Expression<>);
                var fType = typeof(Func<,>);
                var fgType = fType.MakeGenericType(t, typeof(object));
                var egType = eType.MakeGenericType(fgType);

                var eArray = Array.CreateInstance(egType, 0);

              var result = genericMethodInfo.Invoke(mapper, new object[] { stuff, null, eArray }) as IQueryable<dynamic>;

result variable contains a query and when I do result.ToList() then it maps all the properties but not the custom field which are coming always Null because I have not mapped their values to come from.
To unsubscribe from this group and stop receiving emails from it, send an email to automapp...@googlegroups.com.

Tushar Dabhi

unread,
Jul 22, 2022, 2:57:39 PM7/22/22
to AutoMapper-users
What was the solution?

Leonardo Neves

unread,
Mar 22, 2023, 5:56:26 PM3/22/23
to AutoMapper-users
have a solution?
Reply all
Reply to author
Forward
0 new messages