2012-07-20 57 views
4

我是新來的整個ASP世界,我通過構建一個C#MVC3/EF4項目讓我的腳溼了。我發現很難避免在我的模型中複製一堆代碼並查看模型。考慮一個對象Foo。我需要用Foo做以下事情:架構:避免MVC /實體框架項目中重複的模型/模型視圖代碼

  1. 在我的數據庫中存儲Foo類型的記錄。
  2. 允許用戶查找單個Foo的記錄(將Foo的實例傳遞給視圖)。
  3. 允許用戶創建Foo的新實例(將Foo的實例傳遞給表單)。

比方說,我也有一個類型欄。一個酒吧包含一個Foos列表。這裏有兩個要求:

  1. 用戶可以查看酒吧列表。
  2. 當用戶點擊一個特定的欄時,它會顯示它的所有Foos。

所以,我的基本對象的素描像這樣:

class Foo 
{ 
    string FooName; 
    int Id; 
} 

class Bar 
{ 
    List<Foo> FooList; 
    int Id; 
    string Baz; 
} 

但是,當我開始思考不同的看法,它開始變得混亂:

  • 的意見不該沒有任何數據成員的寫權限。
  • 有一個視圖需要一個酒吧列表,但不關心Bar.FooList。比方說,我也想要善於管理資源並儘快關閉DbContext(即在對象存儲在內存中但在呈現視圖之前)。如果我只是通過一個Bars列表並且設計者試圖錯誤地訪問FooList,我們會得到一個運行時錯誤。呸!

好吧,我只是創建一個獨特的ViewModel爲每個視圖,只讀數據成員,沒有問題。

  • 然而無論是數據庫模型和形式模型將需要連接DataAnnotations這不能不說這是必填字段,字符串等的最大長度。如果我創建單獨的形式模型和數據庫模型,然後我最終複製所有這些註釋。呸!

所以,這是我的架構困境:我想要有簡潔的視圖模型,它將視圖限制爲僅讀取他們應該訪問的數據。我想避免重複數據註釋到處。我希望能夠儘快釋放我的數據庫資源。什麼是實現我的目標的最佳方式?

回答

0

我的建議是不要在您的EF實體類中使用數據註釋。相反,嘗試流暢的API。它將模型類本身的持久性問題保留下來。你甚至可以在一個完全不同的庫中定義模型構建器的東西。

至於有重複的屬性,屬性是便宜:

public string MyProp { get; set; } 

不是很多代碼,你可能會開始看到的的ViewModels和實體不必總是彼此的確切的重複。例如,如果您想將[HiddenInput]應用於視圖模型,使其呈現爲<input type="hidden" />?你會將它應用於實體嗎?爲什麼?它屬於viewmodel(命名空間甚至是System.Web.Mvc,而不是System.ComponentModel.DataAnnotations)。

至於在驗證過程中複製錯誤消息(如果您單獨驗證MVC和EF層),則可以使用resx資源。

至於釋放數據庫資源,讓EF管理。我發現每個HttpContext最好保留一個DbContext實例。你可以使用工廠,OnActionExecuting操作過濾器,Application_BeginRequest,IoC容器或其他任何東西來打開它。然後在OnResultExeed,Application_EndRequest等處理上下文。保持簡單。

+0

感謝您的回覆!我同意像HiddenInput這樣的東西不屬於實體。但是對於數據庫和表單都適用的屬性呢,比如MaxLength呢? – 2012-07-20 17:07:14

+0

我使用流暢的API,所以我決不會把maxlength屬性放在實體類上。相反,我會在OnModelCreating期間在實體屬性上調用'.HasMaxLength(int)'。我不再對視圖模型使用數據註解,現在選擇FluentValidation。但是,通過讓這兩個圖層的公共共享文件具有類似'public const int MyPropertyLength = 140;'的類型的值,可以保持這兩個圖層之間的長度屬性一致。然後EF和MVC都可以在屬性,方法調用,消息等等中引用該const。 – danludwig 2012-07-20 17:18:40

+0

我不明白如何使用EF Fluent API幫助您進行DRY?您仍然必須在EF模型和ViewModel上定義'MaxLength'(例如),否則模型狀態將不會自動填充正確的錯誤以發回給用戶。我在這裏面對同樣的挑戰。我知道'BindAttribute',但我不喜歡使用基於字符串的東西。 – 2016-06-16 15:26:51