Asp.net-Mvc

關於使用 ASP.NET MVC/Entity Framework 進行 POCO 驗證的建議

  • January 27, 2011

這是場景:

  • ASP.NET MVC2 Web 應用程序
  • 實體框架 4(純 POCO,自定義數據上下文)
  • 儲存庫模式
  • 工作單元模式
  • 依賴注入
  • 服務層中介控制器 -> 儲存庫

所以基本上,所有很酷的東西。:)

基本 UI 操作(“添加文章”)的事件流:

  1. 控制器在服務層呼叫Add(Post)方法
  2. 服務層在儲存庫上呼叫Add(T)
  3. 儲存庫在自定義數據上下文中呼叫AddObject(T)
  4. 控制器在工作單元上呼叫Commit()

現在,我正在嘗試找出我可以在哪裡進行驗證。

在這個階段,我需要兩種類型的驗證:

  1. 簡單、獨立的 POCO 驗證,例如“文章必須有標題”。這似乎很適合POCO 上的數據註釋
  2. 複雜的業務驗證,例如“無法對鎖定的文章添加評論”。數據註釋無法做到這一點。

現在,我一直在閱讀 Julie Lerman 的“Programming Entity Framework, Second Edition”(順便說一句,這本書很棒),並且一直在研究掛鉤SavingChanges事件以執行“最後一分鐘”驗證。這將是確保每當我做“某事”(添加、修改、刪除)時總是發生驗證的好方法,但這也有點晚了 IMO(因為這些項目已經在狀態管理器中) - 所以如果驗證失敗,刪除它們?

我當然可以讓我的 POCO 實現一個介面(比如“IValidatable”),並在這個事件期間呼叫這個介面上的一個方法。

但這對於商業驗證來說似乎“為時已晚”——這是共識嗎?

我基本上在這裡尋找指導,我正在嘗試為複雜的業務邏輯設計一個可重用的智能驗證方案,考慮到我的上述架構。

另一個曲線球- 如你所知,帶有 EF 的 POCO 意味著 POCO 具有數據庫上的所有屬性 - 所以我可能有一個帶有 get/set 訪問器的“PostID”屬性(因為 EF 需要獲取/設置這些屬性)。

但問題是,“PostID”是一個身份列,那麼我如何保護該欄位不被明確設置?例如,如果我(出於某種原因)執行以下操作:

var post = service.FindSingle(10);
post.PostId = 10;
unitOfWork.Commit();

這將引發 SqlException。我怎樣才能防止這種情況?我不能“隱藏”該屬性(使其成為私有的,甚至是內部的),因為 POCO 位於儲存庫的單獨程序集中。

關於驗證的說明 - 我計劃創建自定義異常(源自異常)。所以當驗證失敗時,我需要拋出這些異常。

這樣,我可以在我的控制器上編寫這樣的程式碼:

[HttpPost]
public ActionResult AddPost(Post post)
{
  try
  {
     IUnitOfWork uow = new UnitOfWork();
     postService.Add(post);
     uow.Commit();
  }
  catch(InvalidPostOperation ipo)
  {
     // add error to viewmodel
  }
}

每次添加時我都必須在服務層上手動進行驗證嗎?那我該如何處理保存?(因為這是在工作單元上,而不是在服務層上)。

因此,為了防止這成為“無處不在”的問題,這是我的問題:

  1. 簡單的 POCO 驗證 - 應該使用數據註釋來完成嗎?優點/缺點/陷阱?
  2. 在什麼情況下(如果有)我們應該掛鉤到 EF 數據上下文的SavingChanges事件以提供驗證?
  3. 我應該在哪裡執行複雜的業務驗證?在服務中,或POCO上的方法(我可以從服務中呼叫)。如何創建智能/可重用方案?
  4. 我們如何“隱藏” POCO 的自動生成屬性不被篡改?

任何想法將不勝感激。

如果這篇文章“太長”,請道歉,但這是一個重要問題,可以通過多種方式解決,所以我想提供所有資訊以獲得最佳答案。

謝謝。

編輯

以下答案很有幫助,但我仍在(理想情況下)尋找更多想法。還有誰?

  1. 就像你說的那樣,DataAnnotations並不適合所有情況。根據我的經驗,缺點主要是複雜的驗證(多個屬性和多個屬性不同的對象)。
  2. 如果我是你,我會盡可能將業務/域驗證排除在數據層 (EF) 之外。如果有數據層驗證場景,那麼很好(例如,驗證複雜的父/子關係——這純粹是數據庫的東西)。
  3. 是的,複雜的業務驗證應該在服務層或模型對像中(通過部分類或某些繼承方法附加:介面/派生類)。ActiveRecord 人員、Repository Pattern 人員和 DDD 人員之間對此存在爭議,但選擇適合您的、簡單的、能夠實現快速部署和低成本應用程序維護的方法。這是一個簡單的範例,說明如何將更複雜的驗證附加到域對象但仍與DataAnnotations介面兼容,因此是“MVC 友好的”。
  4. 好問題。-我還沒有找到一個我 100% 滿意的解決方案。我玩過私人二傳手的想法,但不是很好。快速閱讀這本Evans DDD 總結書。這是一個很好的快速閱讀,它可能會提供一些關於模型對象和值對象之間的目的和區別的見解。這就是我認為對象設計將減輕您對屬性“篡改”(如您所說)但不修復屬性可見性的問題的地方。即,另一種解決方案可能在別處。希望這可以幫助。

引用自:https://stackoverflow.com/questions/3878112