2013-12-13 49 views
1

從我以前的問題分離 - >How to map .NET function call to property automatically?如何使用Automapper函數調用遞歸地將實體映射到視圖模型?

我有一些相關的實體對象,我想映射到視圖模型,並且每個映射到視圖模型需要調用映射的函數。

棘手的部分是實體函數返回需要映射到它的視圖模型的另一個實體。流程有點像這樣。

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

這裏是類,我試圖遞歸地構建一個填充每個對象的嵌套集。

實體:

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;} 
} 

視圖模型:

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;} 
} 
+0

我建議你不要車型不調用數據庫...如果實體具有常規屬性,它們都可以正常工作 –

+0

如果您想從模型中直接調用數據庫,那麼您也可以使用延遲加載的只讀模式,只有財產而不是公共方法使映射更容易一些。下面是一個例子(對不起,它在一行中):'private Item _product; public Item Product {get {return _product ?? (_product = Repository.Get (ProductId)); }}' – valverij

+0

我使用Redis並遵循ServiceStack示例使用的模式。不確定如何在不引入大量新代碼的情況下進行重構。 https://github.com/ServiceStack/ServiceStack.Redis/blob/master/tests/ServiceStack.Redis.Tests/Examples/BestPractice/BlogPostBestPractice.cs – user3092978

回答

3

如果你願意改變你的模型了一下,運行AutoMapper應該是很容易的(如果不是,請跳到下到谷底)。

首先,由於您的評論表明您需要從您的模型調用存儲庫,所以我建議將其更改爲只讀屬性。例如:

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); 
    } 
} 

另外,如果你不想打數據庫時候你叫.Item,那麼你可以添加一個延遲加載支持字段:

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); 
    } 
} 

從那裏,您可以設置AutoMapper是這樣的:

// 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); 

如果你不想改變你的模型使用屬性(或者,如果你不能),那麼你可以添加請使用t他ForMember在地圖上,配置指定什麼爲每個項目做:

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

我試着將我的模型切換到懶加載版本,但我越來越嘗試保存CartItem時發生錯誤,因爲Item屬性拋出錯誤。我相信這是由於Repository爲空。它有可能沒有被注入很快嗎?錯誤:對象引用未設置爲對象的實例。 + \t \t項目\t'this.Item'拋出了'System'類型的異常。NullReferenceException' – user3092978

+0

如果是存儲庫,只要確保在創建對象(定義或構造函數中)時實例化存儲庫即可。如果不是這樣,請確保在調用'.Item'之前定義了您的'ItemID'。如果您仍然遇到問題,您可能需要嘗試保留這些方法,並使用AutoMapper的'ForMember'配置從中取出。 – valverij

3

你不需要做複雜的事情,AutoMapper支持這一點:

// 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); 
相關問題