2011-11-30 88 views
3

我使用ASP.NET MVC 3,Raven DB作爲後臺數據存儲。我有一組模型,我有興趣轉換成ViewModels。爲了做到這一點,我利用AutoMapper來處理將每個屬性映射到ViewModel中的相應屬性的骯髒工作。比方說,我有一個模型,如下所示:ASP.NET MVC模型與其他輔助實體的viewmodel映射

public class FooModel 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public int AlphaId { get; set; } 
    public int BetaId { get; set; } 
} 

然後讓說,我想將其改造成一個ViewModel像這樣:

public class FooViewModel 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public int AlphaId { get; set; } 
    public Alpha Alpha { get; set; } 
    public int BetaId { get; set; } 
    public Beta Beta { get; set; } 
} 

我的地圖,然後建立這樣的應用程序啓動時:

Mapper.CreateMap<Foo, FooViewModel>(); 

然後,在控制器我執行地圖像這樣:

public ActionResult FooDetails(string id) 
{ 
    using(var session = this.documentStore.OpenSession()) 
    { 
     var fooInstance = session.Load<Foo>(id); 
     var fooViewModel = Mapper.Map<FooViewModel>(fooInstance); 
     return this.View(fooViewModel); 
    } 
} 

問題是,正如您在上面看到的那樣,來自存儲庫的實體有兩個屬性,它們是Alpha和Beta類型的其他對象的關鍵字。我對基於AlphaId和BetaId鍵的Alpha和Beta感興趣。

起初我以爲我會利用AutoMapper的自定義轉換功能,但我不認爲這將工作,因爲我們需要將數據會話注入到映射中(以調用數據存儲以檢索Alpha或Beta對象)。

另一種選擇是隻做控制器操作中的所有工作,但這很快就會變得笨重(不是在給出的具體示例中,但這只是一個例子來說明這一點)。

Alpha和Beta的水合應該在哪裏發生,這裏有什麼好的模式?

回答

1

它可能不是理想的,但你可以不只是創建兩個引用的地圖,並在事後映射它們。你仍然需要單獨打電話給他們,但是你讓AutoMapper做沉重的映射,而不是用你自己的地圖填充你的控制器。

public ActionResult FooDetails(string id) 
{ 
    using(var session = this.documentStore.OpenSession()) 
    { 
     var foo = session.Load<Foo>(id).Include(....); 
     var alpha = session.Load<Alpha>(foo.AlphaId); 
     var beta = session.Load<Beta>(foo.BetaId); 

     // null checks 

     var fooViewModel = Mapper.Map<FooViewModel>(foo); 
     fooViewModel.Alpha = Mapper.Map<AlphaViewModel>(alpha); 
     fooViewModel.Beta = Mapper.Map<BetaViewModel>(beta); 

     return View(fooViewModel); 
    } 
} 

我沒有使用AutoMapper所有的東西,但也許你可以通過在孩子通過地圖功能(食CreateMap的ForMember鏈)的對象?也許亞歷山大的AfterMap建議可能會起作用,但我沒有看到如何在控制器動作內部沒有創建地圖的情況下爲被引用的孩子提供水合物(但是你可以直接使用ForMember和Raven會話並且只有一個Mapper.Map)。

加法 - AutoMapper文檔爲嵌套/子地圖提供了類似的方法 - https://github.com/AutoMapper/AutoMapper/wiki/Nested-mappings。雖然它更類似於對象引用,而不是對象ID引用情況。

我不能評論其他答案,但關於帕維爾的答案 - 你並沒有真正使用Raven那樣,沒有o/r映射(除了內部的JSON - >對象)或者數據訪問層,您只需直接使用Raven會話(也許通過服務,但是確實不需要存儲庫或類似的)。關於引用,字節是正確的,當他評論其他答案時,最好的方法是存儲一個id引用並使用Raven包含 - 這是相同的結果,並且仍然只使用一個請求。

0

您可以做的一個優化是從RavenDB一次性加載相關文檔,而不是單獨調用以加載每個相關文檔。請參閱RavenDB文檔here

我想不出任何其他方式來映射這些實體,而不是像在控制器中那樣進行映射。

+0

我已經這樣做了,在查詢期間利用包含。你仍然必須打電話。然而,加上參考實體,讓我們陷入了原始的困境。 –

+0

你可以看看建立在RavenDB之上的HibernatingRhinos的RacoonBlog應用程序,看看它們是如何管理這個的。這裏是一個[示例](https://github.com/ayende/RaccoonBlog/blob/master/RaccoonBlog.Web/Controllers/PostDetailsController.cs) –

2

我同意的人在那裏,但如果你不能擴展你的模型,你總是可以AfterMap這樣定義的映射:

Mapper.CreateMap<Foo, FooViewModel>() 
.AfterMap(MapAlphaBetaFromFooToFooViewModel); 


public void MapAlphaBetaFromFooToFooViewModel(Foo foo, FooViewModel fooViewModel) 
{ 
// Here the code for loading and mapping you objects 
} 

這樣,當你會做的映射,基本映射完成後,Automapper將自動運行該方法。

+1

答案的順序可以改變,所以「人在那裏」不是很好翔實。例如,我把你的答案看作第一個答案。 –

+0

這仍然需要一些關於在automapper中從RavenDB中檢索數據的知識,這並不容易。我不知道有一個更好的方法來做到這一點,除了automapper完成它的工作之外 – KallDrexx

0

你應該首先關心你的架構。從數據庫加載數據是數據訪問層的責任,它不應該知道你的UI是如何組織的。

我認爲,最好的辦法是責任的分配如下:

  1. 數據訪問層有一個基於POCO的模型,其中實體具有相互替代的標識符引用。這個模型暴露於更高層(例如視圖模型)。
  2. DAL有一個加載預期操作所需的所有數據的單一方法。在你的情況下,它應該加載Foo,Alpha,Beta實體。由於這發生在DAL的一種方法中,因此可以在單個數據庫查詢中執行此操作。雖然主要的技巧是其他層不關心它如何工作。
  3. 然後,在您的控制器中,使用AutoMapper將FooModel對象變爲FooViewModel,這是Automapper功能之一。

的關鍵點是:

  1. 只有DAL知道它是如何加載數據。如有必要,您可以根據需要修改它,而無需修改與AutoMapper相關的代碼。
  2. AutoMapper只將數據從一個結構映射到另一個結構,不會影響數據加載策略。

儘管如此,我只會修改FooModel:

public class FooModel 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public Alpha Alpha { get; set; } 
    public Beta Beta { get; set; } 
} 

,並從數據庫加載它的代碼。然而,您可能需要您的原始類似FooModel的結構,例如,定義一個對象關係映射到該簡單結構。但仍然完全取決於DAL。