how to map an anonymous object to a class by AutoM

2019-02-04 01:25发布

问题:

I have an entity:

public class Tag {
    public int Id { get; set; }
    public string Word { get; set; }
    // other properties...
    // and a collection of blogposts:
    public ICollection<Post> Posts { get; set; }
}

and a model:

public class TagModel {
    public int Id { get; set; }
    public string Word { get; set; }
    // other properties...
    // and a collection of blogposts:
    public int PostsCount { get; set; }
}

and I query the entity like this (by EF or NH):

var tagsAnon = _context.Tags
    .Select(t => new { Tag = t, PostsCount = t. Posts.Count() })
    .ToList();

Now, how can I map the tagsAnon (as an anonymous object) to a collection of TagModel (e.g. ICollection<TagModel> or IEnumerable<TagModel>)? Is it possible?

回答1:

Yes, it is possible. You would have to use the DynamicMap method of the Automapper's Mapper class for each anonymous object you have. Something like this:

var tagsAnon = Tags
    .Select(t => new { t.Id, t.Word, PostsCount = t.Posts.Count() })
    .ToList();

var tagsModel = tagsAnon.Select(Mapper.DynamicMap<TagModel>)
    .ToList();

Update: DynamicMap is now obsolete.

Now you need to create a mapper from a configuration that sets CreateMissingTypeMaps to true:

var tagsAnon = Tags
    .Select(t => new { t.Id, t.Word, PostsCount = t.Posts.Count })
    .ToList();

var config = new MapperConfiguration(cfg => cfg.CreateMissingTypeMaps = true);
var mapper = config.CreateMapper();

var tagsModel = tagsAnon.Select(mapper.Map<TagModel>)
    .ToList();


回答2:

I am not entirely sure if this is possible. Suggestions:

Why can't you just do this:

var tagsAnon = _context.Tags
    .Select(t => new TagModel { Tag = t, PostsCount = t. Posts.Count() })
    .ToList();

This SHOULD work, however it fails (I have read that DynamicMap is iffy on collections.

var destination = Mapper.DynamicMap<IEnumerable<TagModel>>(tagsAnon);

This proves that DynamicMap does work with anon types, just not seemingly with enumerables:

var destination = Mapper.DynamicMap<TagModel>(tagsAnon);


回答3:

You can create a custom function to achieve this with latest Automapper. It uses the CreateMissingTypeMaps property as mentioned in other answers above.

public static List<T> MapDynamicList<T>(IEnumerable<object> obj)
    {
        var config = new MapperConfiguration(c => c.CreateMissingTypeMaps = true);
        var mapper = config.CreateMapper();

        var newModel = obj.Select(mapper.Map<T>).ToList();

        return newModel;
    }

Then you just call the function with this single line of code:

var viewModel = Models.Helper.MapDynamicList<MatchSubCategory>(model);

where model is the IEnumerable<object> or List<object>.