11

I have something like this

public class ProductViewModel
{
  public int SelectedProductId { get; set; }
  public string ProductName {get; set;}
  public int Qty {get; set;}
   public List<SelectListItem> Products { get; set}; 
}

I have a domain like this

public class Product
{
  public int ProductId {get; set;}
  public string ProductName {get; set;}
  public int Qty {get; set;}
}


public class Store
{
  public Product() {get; set;}
}

Now I need to do the mapping.

// in my controller

var result = Mapper.Map<ProductViewModel, Store>(Product);

this won't bind anything since it can't figure out how to put the ProductId in since it is

Store.Product.ProductId;

My map is like this

Mapper.CreateMap<ProductViewModel, Store>().ForMember(dest => dest.Product.ProductId, opt => opt.MapFrom(src => src.SelectedProductId));

I get this error

Expression 'dest => Convert(dest.Product.SelectedProductId' must resolve to top-level member. Parameter name: lambdaExpression

I am unsure how to do this.

chobo2
  • 83,322
  • 195
  • 530
  • 832
  • Can you fix up your code? You have a lot of errors in there. For example, `public class MyTest()` is not a valid class declaration, and `public MyTest() { get; set;}` is not a valid property declaration. – Daniel T. Feb 08 '11 at 03:16
  • Are you intentionally mapping from your view model back to your domain class? That is not recommended by the automappers guys. – Brian Cauthon Feb 08 '11 at 17:53
  • 2
    @Brian - Ya. Why not? I mean I thought that is the whole point of auto mapper. Otherwise I have to make all the stuff by hand defeating the purpose of auto mapper. Then I might as well just map domain to view model by hand as well. – chobo2 Feb 08 '11 at 17:57
  • 1
    See this [SO Question](http://stackoverflow.com/questions/2206005/how-to-map-view-model-back-to-domain-model-in-a-post-action) about mapping from the view model back to the domain. I also don't know why you would want to map a productview to a store. Why not just map it back to an actual product. This is a good example of why automapper doesn't map back to the domain well. Everyone expects it to work differently. Mapping from domain to viewmodel is much more straight forward since they tend not to have many levels of nested objects. – Brian Cauthon Feb 08 '11 at 18:21

4 Answers4

25

To Map nested structures, you just need to create a new object in the MapFrom argument.

Example

Mapping:

Mapper.CreateMap<Source, Destination>()
      .ForMember(d => d.MyNestedType, o => o.MapFrom(t => new NestedType { Id = t.Id }));
Mapper.AssertConfigurationIsValid();

Test Code:

var source = new Source { Id = 5 };
var destination = Mapper.Map<Source, Destination>(source);

Classes:

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

public class Destination
{
    public NestedType MyNestedType { get; set; }
}

public class NestedType
{
    public int Id { get; set; }
}
duyker
  • 800
  • 9
  • 17
2

You can use Resolver.

Create a resolver class like that :

class StoreResolver : ValueResolver<Store, int>
{
    protected override int ResolveCore(Store store)
    {
        return store.Product.ProductId;
    }
}

And use it like that :

Mapper.CreateMap<ProductViewModel, Store>()
        .ForMember(dest => dest.SelectedProductId, opt => opt.ResolveUsing<StoreResolver >());

Hope it will help ...

Yazid
  • 21
  • 2
1

The error your getting is because you cannot declare mapping declarations more than one level deep in your object graph.

Because you've only posted one property its hard for me to give you the codes that will make this work. One option is to change your viewmodel property to MyTestTestId and the conventions will automatically pick up on that.

John Farrell
  • 24,673
  • 10
  • 77
  • 110
  • I added some more properties. – chobo2 Feb 08 '11 at 15:39
  • one more thing I changed my stuff around to try to get it to pick up by the conventions but it does not work. I changed SelectedProductId to ProductId and ProductId(in my domain) to Id. Still does not bind. – chobo2 Feb 08 '11 at 17:13
0

The correct answer given by allrameest on this question should help: AutoMapper - Deep level mapping

This is what you need:

Mapper.CreateMap<ProductViewModel, Store>()
    .ForMember(dest => dest.Product, opt => opt.MapFrom(src => src));
Mapper.CreateMap<ProductviewModel, Product>()
    .ForMember(dest => dest.ProductId, opt => opt.MapFrom(src => src.SelectedProductId));

NOTE: You should try to move away from using Mapper.CreateMap at this point, it is obsolete and will be unsupported soon.

Community
  • 1
  • 1
Kevat Shah
  • 119
  • 1
  • 12