Barry Franklin
Barry Franklin

Reputation: 1820

Automapper not mapping navigation properties with Queryable Extensions

I have two classes (simplified for example):

public class Product
{
    public Guid ProductId {get;set;}
    public Guid? ProviderId {get;set;}
    public Provider Provider {get;set;}
    public AssetType AssetType { get; set; }
    public Login Login { get; set; }
}

public class Provider
{
    public Guid ProviderId {get;set;}
    public string ProviderName {get;set;}
    public ICollection<Product> Product {get;set;}
}

The mappings look like this:

cfg.CreateMap<Product, Models.Product>()
.ForMember(m => m.Provider, opt => opt.Ignore())
.ReverseMap();

cfg.CreateMap<Provider, Models.Provider>()
.AfterMap((src, dest) =>
{
    foreach (var i in dest.Product)
        i.Provider = dest;
})
.ReverseMap();

And I have them mapped to identical classes for both the Entities and DTOs. And when I need to map them I do this:

 public IQueryable<Product> GetProducts(int LoginId)
 {
     return adapter.GetProducts(LoginId).ProjectTo<Product>();
 }

The issue is that the Provider object/navigation property is not coming through after the "ProjectTo". I can see it in the adapter, but once it hits "ProjectTo" it loses it.

I try to do it another way like this:

return adapter.GetProducts(LoginId).ToProductModelList();

public static List<Models.Product> ToProductModelList(this IQueryable<Data.Product> _products)
{
    var _list = new List<Models.Product>();
    foreach (var _product in _products)
    {
        var _modelProduct = Mapper.Map<Models.Product>(_product);
        _list.Add(_modelProduct);
    }
    return _list;
}

And it gives me the error:

Error mapping types.

Mapping types:
Provider -> Provider
ASG.Library.Data.Provider -> ASG.Library.Common.Models.Provider

Type Map configuration:
Provider -> Provider
ASG.Library.Data.Provider -> ASG.Library.Common.Models.Provider

Property:
Product

On this line:

  var _modelProduct = Mapper.Map<Models.Product>(_product);

So I'm guessing that "ProjectTo" doesn't work for Data.Provider => Models.Provider because of this error, but it just doesn't throw for that...

I am not sure what to do here. I have other objects or lists of objects in these classes, like AssetType and Login, that comes through just fine, but I can't figure out why this one is causing this error and I don't even know where to start.

I'm using Entity Framework 6. Automapper 6.1.1.0 with Automapper for EF6.

Upvotes: 0

Views: 1462

Answers (1)

Barry Franklin
Barry Franklin

Reputation: 1820

This turns out to be a recursive error. I can't have both a provider on a product and a list of products on a provider. Automapper can't map to infinity... so I just ignore the List<Product> on the provider and now it works.

EDIT:

You can use MaxDepth like this with ProejctTo<>:

cfg.CreateMap<Product, Models.Product>()
.ForMember(m => m.Provider, opt => opt.Ignore())
.MaxDepth(1)
.ReverseMap();

cfg.CreateMap<Provider, Models.Provider>()
.AfterMap((src, dest) =>
{
    foreach (var i in dest.Product)
        i.Provider = dest;
})
.MaxDepth(1)
.ReverseMap();

But this only really gets you a Provider off of a product or a list of Products off of a provider, what it doesn't do is get a list of products off of a provider off of a product.

Provider => List<Product>

Product => Provider

X Product => Provider => List<Product>

I haven't tried PreserveReferences without ProjectTo<>, but according to the AM guide it should be automatic with 6.1.0. I want to use `ProjectTo' anyway and the depth of 1 is fine with me.

Upvotes: 1

Related Questions