2009-09-20 91 views
5

我一直在瀏覽教程(特別是使用Linq-To-Entities的教程),並且我理解基本概念,但有些東西給我提出了一些問題。我的ASP.NET MVC應用程序結構是否正確?

本教程通常只涉及簡單的模型和形式,只使用基本的創建,更新和刪除語句。我的情況稍微複雜一點,我不確定我是否正確地做這件事,因爲當處理六個數據庫對象的關係時,教程停止提供幫助。

對於POST方法,執行CRUD操作

entities.AddToTableSet(myClass); 
entities.SaveChanges(); 

不會做我想做的,因爲完全實現的類不獲取發佈到控制器方法的常用方式。我可能會發布單個字段,表單集合或多個DTO對象,然後調用服務或存儲庫上的方法來獲取我從表單帖子收到的信息以及它需要查詢或創建的信息,然後從所有這些東西,創建我可以保存的數據庫對象。

[AcceptVerbs(HttpVerbs.Post)] 
public ActionResult Add(int id, [Bind(Exclude = "Id")] ClassA classA, 
         [Bind(Exclude = "Id")]ClassB classB) 
{ 
    // Validation occurs here 

    if(!ModelState.IsValid) 
     return View(); 

    try 
    { 
     _someRepositoryOrService.Add(id, classA, classB); 
     return RedirectToAction("Index", new { id = id }); 
    } 
    catch(Exception ex) 
    { 
     // Logging and exception handling occurs here 
    } 
} 


public void Add(int id, ClassA classA, ClassB classB) 
{ 
    EntityA eA = new EntityA 
    { 
     // Set a bunch of properties using the two classes and 
     // whatever queries are needed 
    }; 

    EntityB eB = new EntityB 
    { 
     // Set a bunch of properties using the two classes and 
     // whatever queries are needed 
    }; 

    _entity.AddToEntityASet(eA); 
    _entity.AddToEntityBSet(eB); 
    _entity.SaveChanges(); 
} 

我正確地處理這個問題還是我混蛋框架?我從來沒有直接使用實體對象,每當我查詢一個我在DTO中放置需要的信息並將其視爲基於我的視圖時。創作也一樣。這是允許的,還是我避免使用實體直接違背使用框架的目的?

編輯:我也擔心這種方法,因爲它需要空構造做正確,因爲此錯誤信息的LINQ查詢:

只有參數構造函數和 初始化在LINQ的支持,以 實體。

這不是什麼大不了的事情,因爲我很少需要構造函數中的邏輯int,但是這是沒有構造函數和公共屬性的問題嗎?

+1

Linq to Entities使用的objectcontext使用反射來創建數據映射中的對象,因此很重要,並且要求所有實體都有一個無參數的構造函數,以便可以初始化,如果您希望能夠序列化您的類型也需要一個公共的構造函數 – dmportella 2009-09-28 12:04:30

回答

4

_someRepositoryOrService.Add(id,classA,classB);

我會說你把你的存儲庫與表示層連接起來。這不應該。您的存儲庫只能與實體一起使用。接下來,注意你的Add方法

公共無效添加(INT ID,ClassA的CLASSA,ClassB的CLASSB)的關注(SoC)的

斷裂分離如何。它執行兩個任務:

  1. 地圖視圖數據到實體
  2. 保存到存儲庫

顯然,第一步應該在表示層來完成。考慮使用模型粘合劑。它還可以幫助您解決施工人員的問題,因爲您的模型活頁夾可以瞭解施工要求。

請查看Jimmy Bogard(ASP.NET MVC In Action的作者之一)關於ViewModels的優秀post。這可能會幫助您自動映射。它還提出了一種顛倒的技術 - 讓你的控制器與實體協作,而不是ViewModels!自定義操作過濾器和模型綁定器是消除例程的關鍵,這些例程並不屬於控制器,而是視圖和控制器之間的基礎架構細節。例如,here的我如何自動化實體回顧。 Here是我如何看到控制器應該做什麼。

這裏的目標是讓控制器滿意地管理業務邏輯,把所有不屬於您業務的技術細節放在一邊。你在這個問題中討論的技術約束,你讓他們泄漏到你的代碼中。但是您可以使用MVC工具將它們移動到基礎架構級別。

更新:不,倉庫不應該處理表單數據,這就是我的意思是「與演示文稿結合」。是的,存儲庫位於控制器中,但它們不適用於表單數據。您可以(並非您應該)使用「存儲庫數據」(即實體)進行表單處理,而這正是大多數示例所做的工作。 NerdDinner - 但不是其他方式。這是因爲一般的經驗法則 - 較高層可以與較低層耦合(表現與存儲庫和實體耦合),但從不低層應該耦合到較高層(實體取決於存儲庫,存儲庫取決於表單模型等) )。

第一步應該在存儲庫中完成,這是正確的 - 除了從ClassX到EntityX的映射不屬於該步驟。它正在映射關注點 - 一個基礎設施。例如,請參閱this有關映射的問題,但通常如果您有兩層(UI和存儲庫),則不應關心映射 - 映射器服務/幫助器應該。除了Jimmy的博客,您還可以閱讀ASP.NET MVC In Action,或者簡單地看一下他們如何與傳遞給控制器​​構造函數的IEntityMapper接口進行映射(請注意,這是Jimmy Bogard的AutoMapper更爲人工且工作量較少的方法)。

還有一件事。閱讀關於領域驅動設計,尋找文章,向他們學習,但你不必去關注一切。這些是準則,而不是嚴格的解決方案看看你的項目是否可以處理這個問題,看看你是否可以處理這個問題,等等。嘗試應用這些技術是因爲它們通常是優秀且經過批准的開發方式,但不要盲目採取 - 最好是在學習的過程中比應用不理解的東西更好。

+0

對於耦合存儲庫,我不確定你的意思,在控制器中擁有一個存儲庫似乎是大多數教程所做的。至於表示層中的第一步,不應該在存儲庫中完成嗎?我認爲存儲庫的目的是擔心處理表單數據到數據庫轉換? – Brandon 2009-10-01 06:31:54

+0

也感謝你的例子和建議。我沒有時間去實際做出改變,但這是一個很好的方向。 – Brandon 2009-10-01 06:33:16

+0

查看更新。我建議慢慢重構,例如首先做_realEntityRepository.Add(EntityMapper.From(classA)); (或classA.MapToEntity()),然後涉及自定義ModelBinder(這是一個很大的話題),然後添加IoC容器(另一個大話題)等等。 – queen3 2009-10-01 10:10:36

4

我會說使用DTO和使用您自己的數據訪問方法和業務層包裝實體框架是一個好方法。您最終可能會編寫大量代碼,但它比假裝實體框架生成的代碼是您的業務層更好。

這些問題並不一定以任何方式綁定到ASP.NET MVC。 ASP.NET MVC基本上沒有提供關於如何進行模型/數據訪問的指導,ASP.NET MVC的大多數示例和教程都不是有生產價值的模型實現,但實際上只是最小的樣本。

看起來你正處在正確的軌道上,繼續前行。最終,您最常使用實體框架作爲代碼生成器,它不會生成非常有用的代碼,因此您可能需要查看其他代碼生成器或更符合您需求的工具或框架。

+0

我真的只使用實體框架來嘗試新的東西。我用於使用nHibernate。對於我應該使用的更好的發生器或框架,你有什麼建議嗎? – Brandon 2009-09-20 19:32:49

+0

我不知道有什麼東西可以滿足您的需求。其中一些是商業的,一些是免費的。沒有特別的順序:T4模板,CodeSmith,LLBLGen Pro。 – 2009-09-21 07:15:06

+1

這主要是一個非常好的答案(+1),但我不同意他使用實體框架作爲代碼生成器。更重要的是他正在使用實體框架將他的數據庫映射到對象空間。即使您從未實際實現實體類型,這也很重要;當您將它們投影到其他類型時,仍然在您的LINQ to Entities查詢中使用映射實體。 – 2009-09-21 13:38:24

相關問題