1

According to the documentation PreserveReferences should be set automatically whenever possible for AutoMapper.

Starting from 6.1.0 PreserveReferences is set automatically at config time whenever possible.

https://github.com/AutoMapper/AutoMapper/wiki/5.0-Upgrade-Guide

I have also tried setting MaxDepth to 1 but I still get a stack overflow exception with the following mapping. Can I get around this somehow or do I need to modify the view models?

cfg.CreateMap<ArticleViewModel, Article>(MemberList.Source)
    .MaxDepth(1)
    .EqualityComparison((src, dst) => src.Id == dst.Id);

Code that causes the stack overflow exception:

var article = await iArticleRepository.GetAsync(id);
//The mapping below causes the exception
var mappedArticle = Mapper.Map<ArticleViewModel>(article);

Entities:

public class Article: IEntity<int>
{
    [Key]
    public int Id { get; set; }

    ...

    public int SupplierId { get; set; }

    public virtual Supplier Supplier { get; set; }
}

public class Supplier: IEntity<int>
{
    [Key]
    public int Id { get; set; }

    ...

    public virtual ICollection<Contact> Contacts { get; set; }
}

public class Contact: IEntity<int>
{
    [Key]
    public int Id { get; set; }

    ...
    public virtual ICollection<Supplier> Suppliers { get; set; }
}

View models:

public class ArticleViewModel
{
    public int Id { get; set; }

    ...
    public SupplierViewModel Supplier { get; set; }

}

public class SupplierViewModel
{
    public int Id { get; set; }

    ...
    public List<ContactViewModel> Contacts { get; set; }

}

public class ContactViewModel
{
    public int Id { get; set; }
    ... 
    public List<SupplierViewModel> Suppliers { get; set; }
}
Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Ogglas
  • 62,132
  • 37
  • 328
  • 418
  • Your Contact entity has a collection of other Contacts while your ContactViewModel has a collection of SuplierViewModels. Is that correct? – Fabiano Jul 20 '17 at 12:42
  • @Fabiano Thanks for noticing and no it should of course be Suppliers. Updated now. – Ogglas Jul 20 '17 at 12:44
  • Hopefully for people who have hundreds of CreateMap (like us) it is possible to add PreserveReferences for all maps with one single line of code : cfg.ForAllMaps((typeMap, mappingExpression) => mappingExpression.PreserveReferences()); Unfortunately doing so we won't benefits of performance improvement. – bN_ Oct 19 '17 at 12:42

1 Answers1

3

Well, it's unclear what does whenever possible mean. Since the documentation before that states

It turns out this tracking is very expensive, and you need to opt-in using PreserveReferences for circular maps to work

looks like your scenario fails into not possible category :)

Let not rely on that and use the explicit opt-in. The circular reference in this sample model is between Supplier and Contact, so you have to specify in one of the involved class mappings, for instance:

cfg.CreateMap<ArticleViewModel, Article>(MemberList.Source)
    .MaxDepth(1)
    .EqualityComparison((src, dst) => src.Id == dst.Id);

cfg.CreateMap<SupplierViewModel, Supplier>(MemberList.Source)
    .PreserveReferences()
    .EqualityComparison((src, dst) => src.Id == dst.Id);
Ogglas
  • 62,132
  • 37
  • 328
  • 418
Ivan Stoev
  • 195,425
  • 15
  • 312
  • 343
  • Thanks. I tried with this before but without MaxDepth. When using both however it worked! Will update your answer and mark as accepted. – Ogglas Jul 20 '17 at 13:54