AutoMapper nested mapping

Posts   
 
    
tbeyhan
User
Posts: 23
Joined: 23-May-2006
# Posted on: 11-Jan-2011 10:17:31   

Hi, I'm planning to use AutoMapper in my new MVC3 protect. Does anyone use it in Nested mapping scenario. I want to map ProductViewModel to ProductEntity with all related child tables.

Any ideas, tunc

Walaa avatar
Walaa
Support Team
Posts: 14952
Joined: 21-Aug-2005
# Posted on: 11-Jan-2011 10:40:31   

I don't have an experience with it, but please check this thread: http://www.llblgen.com/tinyforum/Messages.aspx?ThreadID=17504

tbeyhan
User
Posts: 23
Joined: 23-May-2006
# Posted on: 11-Jan-2011 13:32:44   

Walaa wrote:

I don't have an experience with it, but please check this thread: http://www.llblgen.com/tinyforum/Messages.aspx?ThreadID=17504

Walaa, I can map nested entites to modelviews but failed with reserve. Here is the code i used.

        LLBLGenAutoMapper.Init();
        Mapper.CreateMap<OrdersEntity, Order>();
        Mapper.CreateMap<OrderDetailsEntity, OrderDetail>();
        Mapper.CreateMap<Order, OrdersEntity>();
        Mapper.CreateMap<OrderDetail, OrderDetailsEntity>(); //.ForEntity(true);

        using (DataAccessAdapter dap = new DataAccessAdapter())
        {

            IPrefetchPath2 path = new PrefetchPath2(EntityType.OrdersEntity);
            path.Add(OrdersEntity.PrefetchPathOrderDetails);
            OrdersEntity oe = new OrdersEntity(10249);
            dap.FetchEntity(oe, path);


            var order = Mapper.Map<OrdersEntity, Order>(oe);

            MessageBox.Show("#Details " + order.OrderDetails.Count.ToString());

            var newoe = Mapper.Map<Order, OrdersEntity>(order);


            MessageBox.Show("#Details " + newoe.OrderDetails.Count.ToString());
        }
arschr
User
Posts: 893
Joined: 14-Dec-2003
# Posted on: 11-Jan-2011 14:33:58   

I've used Automapper with great sucess in a few situations. From your code, I think you are trying two way mapping? I don't think that is officially supported by Auotmapper in released versions.

I'm not clear on your statement

but failed with reserve

. Is reserve one of your entities or what?

tbeyhan
User
Posts: 23
Joined: 23-May-2006
# Posted on: 11-Jan-2011 15:30:49   

arschr wrote:

I've used Automapper with great sucess in a few situations. From your code, I think you are trying two way mapping? I don't think that is officially supported by Auotmapper in released versions.

I'm not clear on your statement

but failed with reserve

. Is reserve one of your entities or what?

My fault flushed i should be more clear. Yes i'm trying two way mapping.

arschr
User
Posts: 893
Joined: 14-Dec-2003
# Posted on: 11-Jan-2011 16:20:54   

So the problem is that when you map from order back to OrderEntity the child collection OrderDetails isn't being populated.

You may want to discuss how to fix this in the AutoMapper discussion group http://groups.google.com/group/automapper-users

tbeyhan
User
Posts: 23
Joined: 23-May-2006
# Posted on: 12-Jan-2011 08:01:46   

May be. The shortcut is to map child collections separately and then attach to main entity

var newoe = Mapper.Map<OrderVievModel, OrdersEntity>(order); List<OrderDetailsEntity> od = Mapper.Map<List<OrderDetailViewModel>, List<OrderDetailsEntity>>(order.OrderDetails); newoe.OrderDetails.AddRange(od);

ugly, but works confused

worldspawn avatar
worldspawn
User
Posts: 321
Joined: 26-Aug-2006
# Posted on: 13-Jan-2011 03:28:34   

Not sure why you are doing this. Out of the box automapper fails to map TO entity collections (but will map FROM just fine) due to some weird thing I can't really remember... I think it tries to Set a new entitycollection instance rather than just clear it and add to it. It's described in the post daelmo referenced.

You should be able to write:

Mapper.CreateMap<OrderViewModel, OrderEntity>(); Mapper.CreateMap<OrderDetailViewModel, OrderDetailEntity>();

then just:

var myOrder = Mapper.Map<OrderViewMode, OrderEntity>(order);

Assuming both your model and your entity have a property with the same (eg. OrderDetailUsingOrderId) it should map automagically. Otherwise if they have a different name you will need to have a ForMember telling automapper to map what from where.

I've learnt a bit more about automapper since that old post and I believe creating a Resolver would be a much better solution for mapping TO entitycollections. I might have a look at it this afternoon, need to refresh my memory on the topic.

worldspawn avatar
worldspawn
User
Posts: 321
Joined: 26-Aug-2006
# Posted on: 13-Jan-2011 05:20:21   

Well it seems a resolver just won't work. While I was able to write a resolver that got a reference to the entity and then populated the collection there seems to be no way to stop AutoMapper from then trying to set it, seeing the property isn't settable to it calls Clear instead.

However I've found a reasonable work around. Just map things in AfterMap. Its not brilliant but it does keep it in the mapping definition rather than manually mapping collections in ur main code.


CreateMap<UserEditModel, UserEntity>()
                .ForEntity()
                .AfterMap((m, p) => p.UserGroupUsingUserId.AddRange(Mapper.Map<IEnumerable<int>, IEnumerable<UserGroupEntity>>(m.Groups)));

            CreateMap<int, UserGroupEntity>().ForEntity()
                .ConvertUsing(p => new UserGroupEntity() { GroupId = p });

Walaa avatar
Walaa
Support Team
Posts: 14952
Joined: 21-Aug-2005
# Posted on: 13-Jan-2011 08:44:00   

Thanks for the feedback.

tbeyhan
User
Posts: 23
Joined: 23-May-2006
# Posted on: 13-Jan-2011 09:00:10   

worldspawn wrote:

Well it seems a resolver just won't work. While I was able to write a resolver that got a reference to the entity and then populated the collection there seems to be no way to stop AutoMapper from then trying to set it, seeing the property isn't settable to it calls Clear instead.

However I've found a reasonable work around. Just map things in AfterMap. Its not brilliant but it does keep it in the mapping definition rather than manually mapping collections in ur main code.


CreateMap<UserEditModel, UserEntity>()
                .ForEntity()
                .AfterMap((m, p) => p.UserGroupUsingUserId.AddRange(Mapper.Map<IEnumerable<int>, IEnumerable<UserGroupEntity>>(m.Groups)));

            CreateMap<int, UserGroupEntity>().ForEntity()
                .ConvertUsing(p => new UserGroupEntity() { GroupId = p });

Straightforward and clean thanks smile