简体   繁体   中英

How to recursively map entity to view model with Automapper function call?

Spin off of my earlier question -> How to map .NET function call to property automatically?

I have some related entity objects that I want to map to view models, and each mapping to a view model needs to call a function for the mapping.

The tricky part is that the entity function returns another entity which needs to be mapped to it's view model. The flow is somewhat like this.

CartEntity > CartViewModel > CartEntity.GetCartItems() > CartViewModel.CartItems > CartEntity.GetCartItems().GetItem() > CartViewModel.CartItems.Item > CartEntity.GetCartItems().GetItem().GetProduct() > CartViewModel.CartItems.Item.Product

Here are the classes, where I am trying to recursively build a nested set that is populated with each object.

Entities:

public class CartEntity {
    public long Id {get; set;}
    public List<CartItem> GetCartItems() {
          return Repository.GetAll<CartItem>();
    }
}

public class CartItem {
    public long Id {get; set;}
    public long ItemId {get ; set;}
    public Item GetItem() {
          return Repository.Get<Item>(ItemId);
    }
}

public class Item {
    public long Id {get; set;}
    public long ProductId {get; set;}
    public Item GetProduct() {
          return Repository.Get<Product>(ProductId);
    }
}
public class Product {
    public long Id {get; set;}
}

View Models:

public class CartViewModel {
    public long Id {get; set;}
    public List<CartItemViewModel> {get; set; }
}

public class CartItemViewModel {
    public long Id {get; set;}
    public ItemViewModel Item {get; set; }
}

public class ItemViewModel {
    public long Id {get; set;}
    public ProductViewModel Product {get; set; }
}

public class ProductViewModel {
    public long Id {get; set;}
}

You don't need to do anything complicated, AutoMapper supports this:

// one time config
Mapper.CreateMap<CartEntity, CartViewModel>();
Mapper.CreateMap<CartItem, CartItemViewModel>();
Mapper.CreateMap<Item, ItemViewModel>();
Mapper.CreateMap<Product, ProductViewModel>();
Mapper.AssertConfigurationIsValid();

// whenever you map
CartEntity cart = // whatever
CartViewModel vm = Mapper.Map<CartViewModel>(cart);

If you're willing to change your models a bit, running AutoMapper should be pretty easy (if not, skip down to the bottom).

First, since your comments indicate that you need to call your repositories from your models, I'd suggest changing them to read-only properties. For example:

public class CartItem {
    public long Id {get; set;}

    public long ItemId {get ; set;}

    public Item Item {
        get {
            return GetItem();
        }
    }

    private Item GetItem() {
          return Repository.Get<Item>(ItemId);
    }
}

Also, if you didn't want to hit the database every time you called .Item , then you could add a lazy-loaded backing field:

public class CartItem {
    private Item _item;

    public long Id {get; set;}

    public long ItemId {get ; set;}

    public Item Item {
        get {
            return _item ?? (_item = GetItem());
        }
    }

    private Item GetItem() {
          return Repository.Get<Item>(ItemId);
    }
}

From there, you can set up AutoMapper like this:

// one-time, static configuration:
Mapper.CreateMap<CartEntity, CartViewModel>();
Mapper.CreateMap<CartItem, CartItemViewModel>();
Mapper.CreateMap<Item, ItemViewModel>();
Mapper.CreateMap<Product, ProductViewModel>();

// running the mapper:
var cartViewModel = Mapper.Map<CartViewModel>(cart);

If you don't want to change your models to use properties (or if you can't), then you can add use the ForMember configuration on your maps to specify what to do for each item:

Mapper.CreateMap<CartItem, CartItemViewModel>()
      .ForMember(target => target.Item, x => x.ResolveUsing(source => source.GetItem()));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM