1

How to map User class to UserModel class using Emit Mapper?

    public class User
    {
        public Guid Id { get; set; }

        public string FirstName { get; set; }

        public string LastName { get; set; }

        public IList<Role> Roles { get; set; }

        public Company Company { get; set; }        
    }

    public class UserModel
    {
        public Guid Id { get; set; }

        public Guid CompanyId { get; set; }

        public string FirstName { get; set; }

        public string LastName { get; set; }      

        public IList<RoleModel> Roles { get; set; }
}

There several problems:

  • I need to flatten the object such that I will have CompanyId instead of the Company object.
  • Company object has property Id, in the UserModel I have CompanyId which corresponds to the company id, but property names do not match.
  • I need to map List<Role> to List<RoleModel>
petrov.alex
  • 1,089
  • 2
  • 12
  • 20

2 Answers2

1

To get flattened model you could check this example. But it seems that by default it has a convention of having sub class property name as a prefix in the target.

Source

public class SourceObject
{
public SourceSubObject SomeClass { get; set; }
}

public SourceSubObject
{
    public int Age { get; set; }
}

Target

public class Target
{
public int SomeClassAge  { get; set; }
}

Second, one options is to let the default settings copy those properties that it can copy and manually do the rest

var target = ObjectMapperManager.DefaultInstance.GetMapper<Source, Target>().Map(source);
target.CompanyId = target.Company.CompanyId;

Or if you need to reuse the mapping the create custom mapper

Custom mapper

private Target Converter(Source source)
{
   var target = new Target();
   target.CompanyId = source.Company.CompanyId;
   return target;
}

Usage

var mapper = new DefaultMapConfig().ConvertUsing<Source, Target>(Converter);
var target = ObjectMapperManager.DefaultInstance.GetMapper<Source, Target>(mapper).Map(source);

Update

What comes to the Role & RoleModel mapping. It seems that in this case you need to have Deep copy enabled and depending on the class(es) definitions you can either copy it directly or do some custom mapping.

ObjectMapperManager.DefaultInstance.GetMapper<Source, Target>(new DefaultMapConfig().DeepMap<ClassToDeepMap>().DeepMap<ClassToDeepMap>()).Map(source, target);
Tx3
  • 6,796
  • 4
  • 37
  • 52
0
  • For flattering I was using configuration from the samples in Emit Mapper source files: http://emitmapper.codeplex.com/SourceControl/changeset/view/69894#1192663

  • To make the names to match in Company class should be the field with the name Id

  • For mapping List<Role> to List<RoleModel> I was using custom converter:

    public class EntityListToModelListConverter<TEntity, TModel>
    {
        public List<TModel> Convert(IList<TEntity> from, object state)
        {
            if (from == null)
                return null;
    
            var models = new List<TModel>();
            var mapper = ObjectMapperManager.DefaultInstance.GetMapper<TEntity, TModel>();
    
            for (int i = 0; i < from.Count(); i++)
            {
                models.Add(mapper.Map(from.ElementAt(i)));
            }
    
            return models;
        }
    }
    

    So all together:

     var userMapper = ObjectMapperManager.DefaultInstance.GetMapper<User, UserModel>( 
                 new FlatteringConfig().ConvertGeneric(typeof(IList<>), typeof(IList<>), 
                 new DefaultCustomConverterProvider(typeof(EntityListToModelListConverter<,>))));
    
  • There is a problem, using Flatterning Configuration with Custom converters, check my question: Emit Mapper Flattering with Custom Converters

Community
  • 1
  • 1
petrov.alex
  • 1,089
  • 2
  • 12
  • 20
  • Thanks, that solved my issue. Anyway, it is still not clear to me how I should specify the way TEntity and TModel should be mapped... Let's suppose that I have type A with a collection of type B and I would like to map it to AMapped with a collection of BMapped...how should I setup the configuration? should I use PostProcess? I really like the idea of this library, but it really misses configurations and examples... – fra May 19 '12 at 14:00
  • It depends on the type of the collection. In my example I have a generic collection, so I was using a custom converter for generic types http://emitmapper.codeplex.com/wikipage?title=Customization%20using%20default%20configurator&referringTitle=Documentation&ANCHOR#Custom_converters_for_generics. You need to provide custom converter for converting from B to BMapped, in the case of generics you will register it as `new FlatteringConfig().ConvertGeneric(typeof(B), typeof(BMapped), new DefaultCustomConverterProvider(typeof(CustomConverterClass)))` – petrov.alex May 19 '12 at 15:11
  • In the `Convert` method I am mapping each item of `Role` to `RoleModel` by creating mapper like `var mapper = ObjectMapperManager.DefaultInstance.GetMapper();` and then calling `Map` method on each item and adding the return value to the collection of models – petrov.alex May 19 '12 at 15:16
  • Thank you very much. I understood it better and I'm beginning taking advantage from it. – fra May 20 '12 at 12:38
  • one last thing: that is the "FlatteringConfig" object you used? I couldn't find it. – fra May 20 '12 at 12:49
  • I have downloaded it separately from CodePlex, check the link in my answer (first one). It is the direct link to this file. Also check the last link in my answer, as there was a problem of using this configuration with custom converters – petrov.alex May 20 '12 at 14:23
  • EmitMapper does not work when using interface typed collections. Either you have to configure it or you have to use concrete list instead of interface, what in my opinion is not good...FastMapper does it tho as well as AutoMapper, even tho AutoMapper has a performance issue and is not my favorite! – DAG Dec 26 '15 at 21:53