43

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?

amiry jd
  • 27,021
  • 30
  • 116
  • 215

3 Answers3

63

Update 2019-07-31: CreateMissingTypeMaps is now deprecated in AutoMapper v8, and will be removed in v9.

Support for automatically created maps will be removed in version 9.0. You will need to explicitly configure maps, manually or using reflection. Also consider attribute mapping.


Update 2016-05-11: 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();

Yes, it is possible. You would have to use the DynamicMap<T> 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();
C. Augusto Proiete
  • 24,684
  • 2
  • 63
  • 91
  • 1
    This is deprecated as of AutoMapper 4.1, what to do now? – MobileMon May 03 '16 at 12:46
  • 4
    @MobileMon I've updated the answer with the new way of doing it. Thanks for pointing it out. – C. Augusto Proiete May 11 '16 at 14:28
  • 1
    I can confirm using "CreateMissingTypeMaps = true" works. This answer should be marked as valid. Thanks! – Joan.bdm Apr 07 '17 at 07:02
  • CreateMissingTypeMaps = true works like charm. But is there a good way to create a generic function for this? Something like "private static T MapDynamic(dynamic obj)".. I can't get it right. Any comments? – vohrahul May 20 '18 at 20:48
  • @vohrahul I'm sure I understand your question. Maybe you want to post a new question with more details and more code (even if pseudo-code that doesn't compile) to show what you're trying to do? – C. Augusto Proiete May 21 '18 at 11:28
  • @CaioProiete Hey, I am sorry I forgot to update. But I actually got it to working and posted the same as an answer here on this question itself. – vohrahul May 22 '18 at 14:29
  • 1
    The CreateMissingTypeMaps = true is also deprecated on the 8.1.1.0 version. I guess the easiest way now is to map field by field. – Daniel Lobo Jul 25 '19 at 18:10
  • So with version 9 it's no longer possible to map anon types to a class? Or is there another way? – Jacquers Mar 31 '20 at 15:15
  • @C. Augusto Proiete. CreateMissingTypeMaps is also obsolete in ver > 9. Any suggestions? – jdawiz Jul 08 '21 at 18:07
  • Support for automatically created maps will be removed in version 9.0. You will need to explicitly configure maps, manually or using reflection. Also consider [attribute mapping](http://docs.automapper.org/en/latest/Attribute-mapping.html) – C. Augusto Proiete Jul 08 '21 at 19:30
4

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);
Justin Pihony
  • 66,056
  • 18
  • 147
  • 180
0

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>.

d219
  • 2,707
  • 5
  • 31
  • 36
vohrahul
  • 1,123
  • 10
  • 17
  • Creating a new mapper every time would have a cost to it. It would often be better to assign the mapper-instance to a private static variable. – oddbear Mar 04 '19 at 11:43