2012-05-22 195 views
8

使用我纔剛起步,並在愛我愛上MVC設計模式。MVC減少重複代碼

與它我唯一的寵物怨恨的是,它似乎產生了很多重複的代碼。例如。

我有一個標準的MVC應用程序與我在一個項目DB(型號),從我的另一個控制器/視圖/的ViewModels,從另一個我的檢驗方法再次分離分離。所有工作都很棒。

型號: 現在,我有一幫不錯的EF4班在我的數據庫項目,我必須使用的ViewModels在我真實的項目來訪問我的數據。這裏沒問題。

控制器: 然而,每個控制器我有本質上是做同樣的事情。它得到同時設定的ViewModels數據,因此而每個控制器,它只能獲得不同的數據,他們基本上都在做同樣的工作,在完全相同的方式不同。 (我目前有9個,但是這可能很容易爆炸到50多)。

例如:

public class Dummy1Controller : Controller 
{ 
    private MyProj.Data.Entities _entities = new Data.Entities(); 
    private MyProj.Data.Entities2 _coreEntities = new Data.Entities2(); 

    //GET: /Customers/ 
    public ActionResult Index() 
    { 
     if (_entities.table1.Count() == 0) return View(); 

     var pastObj = _entities.table1.First(); 
     return View(new Table1ViewModel() 
     { 
      Id = pastObj.Id, 
      FirstName = pastObj.FirstName, 
      LastName = pastObj.LastName, 
      . 
      . 
      . 
      . 
     }); 
    } 
} 

public class Dummy2Controller : Controller 
{ 
    private MyProj.Data.Entities _entities = new Data.Entities(); 
    private MyProj.Data.Entities2 _coreEntities = new Data.Entities2(); 

    //GET: /Vehicles/ 
    public ActionResult Index() 
    { 
     if (_entities.table2.Count() == 0) return View(); 

     var pastObj = _entities.table2.First(); 
     return View(new Table1ViewModel() 
     { 
      RegNo = pastObj.RegNo, 
      Make = pastObj.Make, 
      Model = pastObj.Model, 
      . 
      . 
      . 
      . 
     }); 
    } 
} 

public class Dummy3Controller : Controller 
{ 
    private MyProj.Data.Entities _entities = new Data.Entities(); 
    private MyProj.Data.Entities2 _coreEntities = new Data.Entities2(); 

    //GET: /Invoices/ 
    public ActionResult Index() 
    { 
     if (_entities.table3.Count() == 0) return View(); 

     var pastObj = _entities.table3.First(); 
     return View(new Table1ViewModel() 
     { 
      InvNo = pastObj.InvNo, 
      Amount = pastObj.Amount, 
      Tax = pastObj.Tax, 
      . 
      . 
      . 
      . 
     }); 
    } 
} 

瀏覽: 從contollers生成的每個視圖工作的偉大。 Execpt,只有變化的是數據(帶有標籤和文本框的字段)。再次,他們都做同樣的工作(但有不同的數據集)。

@model MyProject.Web.ViewModels.Table1ViewModel 

@{ 
    ViewBag.Title = "Index"; 
} 

<link href="@Url.Content("~/Content/CSS/GenericDetailStyles.css")" rel="stylesheet" type="text/css" /> 

<section id="content"> 
    <div id="table"> 
     <div> 
      <h2>Customer</h2> 
     </div> 
     <div class="row"> 
      <div class="left">@Html.LabelFor(x=>x.Id)</div> 
      <div class="right">@Html.TextBoxFor(model => model.Id)</div> 
     </div> 
     <div class="row"> 
      <div class="left">@Html.LabelFor(x=>x.FirstName)</div> 
      <div class="right">@Html.TextBoxFor(model => model.FirstName)</div> 
     </div> 
     <div class="row"> 
      <div class="left">@Html.LabelFor(x=>x.LastName)</div> 
      <div class="right">@Html.TextBoxFor(model => model.LastName)</div> 
     </div> 
     . 
     . 
     . 
     . 
    </div> 
</section> 

@{Html.RenderAction("Index", "FooterPartial");} 


-------------------------------------------------------------------------------------- 


@model MyProject.Web.ViewModels.Table2ViewModel 

@{ 
    ViewBag.Title = "Index"; 
} 

<link href="@Url.Content("~/Content/CSS/GenericDetailStyles.css")" rel="stylesheet" type="text/css" /> 

<section id="content"> 
    <div id="table"> 
     <div> 
      <h2>Vehicle</h2> 
     </div> 
     <div class="row"> 
      <div class="left">@Html.LabelFor(x=>x.RegNo)</div> 
      <div class="right">@Html.TextBoxFor(model => model.RegNo)</div> 
     </div> 
     <div class="row"> 
      <div class="left">@Html.LabelFor(x=>x.Make)</div> 
      <div class="right">@Html.TextBoxFor(model => model.Make)</div> 
     </div> 
     <div class="row"> 
      <div class="left">@Html.LabelFor(x=>x.PatientID)</div> 
      <div class="right">@Html.TextBoxFor(model => model.Model)</div> 
     </div> 
     . 
     . 
     . 
     . 
    </div> 
</section> 

@{Html.RenderAction("Index", "FooterPartial");} 


-------------------------------------------------------------------------------------- 


@model MyProject.Web.ViewModels.Table3ViewModel 

@{ 
    ViewBag.Title = "Index"; 
} 

<link href="@Url.Content("~/Content/CSS/GenericDetailStyles.css")" rel="stylesheet" type="text/css" /> 

<section id="content"> 
    <div id="table"> 
     <div> 
      <h2>Invoice</h2> 
     </div> 
     <div class="row"> 
      <div class="left">@Html.LabelFor(x=>x.InvNo)</div> 
      <div class="right">@Html.TextBoxFor(model => model.InvNo)</div> 
     </div> 
     <div class="row"> 
      <div class="left">@Html.LabelFor(x=>x.Amount)</div> 
      <div class="right">@Html.TextBoxFor(model => model.Amount)</div> 
     </div> 
     <div class="row"> 
      <div class="left">@Html.LabelFor(x=>x.Tax)</div> 
      <div class="right">@Html.TextBoxFor(model => model.Tax)</div> 
     </div> 
     . 
     . 
     . 
     . 
    </div> 
</section> 

@{Html.RenderAction("Index", "FooterPartial");} 

問題: 我想製作一個控制器,並使其成爲動態的。以便它可以讀取來自不同視圖模型的數據。 (爲什麼有9個或50個控制器esentially做同樣的工作)

然後我想與意見也這樣做。這樣可以動態生成不同的字段。 (爲什麼有9或50個視圖都在做同樣的工作)。如果視圖基於控制器,視圖應該能夠根據其屬性進行更改。

基本上我想要做的就是找到一種方法告訴控制器從viewmodel X或VM - Y或VM - Z中讀取數據,它應該能夠生成屬性,檢索相關數據並傳遞它到接收到的視圖中,將生成帶有標籤和文本框的字段。

我想我想知道是否有任何方式使用反射來做到這一點。由於視圖模型是具有簡單屬性的基本類。我們可能會創建一個基本控制器類,它有一個方法來讀取指定的viewmodel對象,獲取其屬性,讀入關聯的表並將該表中的字段與類中的屬性進行匹配。最後可以從表中傳入記錄來顯示。然後可以使用某種剃鬚刀,c#或JavaScript基於此自動生成視圖。

如果可能或不可以的話,歡迎提供任何幫助。

+0

爲什麼混合使用MVC和MVVM模式?我想我問的是,你需要什麼ViewModel的,不只是通過模型? – Brunner

+0

@Brunner - 首先,它是我展示的方式,我不知道如何直接做到這一點(我對MVC比較陌生)。其次,我的僱員希望這樣做。最後,當我在自己的項目上工作時,我這樣做是因爲我不喜歡將實際的數據庫作爲項目的一部分,如許多示例所示,並使其自動生成或重新生成。很少有實際的例子可以告訴你如何連接到一個真實的在線數據庫。如果你知道任何我會真正appreicate鏈接到他們。感謝您的回覆。 –

+0

我不確定「真實生活dbs」是什麼意思,但您可能想要結合EF查看POCO(例如,Code-First) - 它已經或多或少地已經包裝得很整齊。我也不確定你的意思是沒有在項目中的實際數據庫,給你例如你可以做「返回新視圖(pastObj);」你甚至不用編輯視圖(除@model聲明雖然) – Brunner

回答

10

您可以使用AutoMapper刪除模型/實體之間複製值的所有代碼。另外,請考慮使用佈局,數據註釋屬性和模板(使用Html.DisplayFor和Html.EditorFor)縮小您的視圖。

http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-1-introduction.html

你可以調查創建一個通用基控制器類,將採取模型和實體的類型,並將包含CRUD操作的通用邏輯的可能性,但它可能是有些過分,阻礙稍後您的發展。

+0

@Francis請記住,automapper(或valueinjecter)只能用於單向映射,不建議從post方法返回到實體。它在某些情況下會起作用,但在另一些情況下會分崩離析,說實體框架作爲屬性沒有設置「修改」標誌,但對象本身會這樣做,因此不會導致數據庫返回更改。只是對其他人閱讀而已。 –

+0

@AdamTuliper - 我用AutoMapper和EF沒有任何問題。所有AutoMapper都會調用屬性設置器,與在代碼中手動執行沒有區別。您能否更清楚地瞭解您遇到的問題? –

+0

我使用AutoMapper進行雙向映射,但我不再直接將ViewModel映射到實體。我們的實體現在擁有'保護內部集合',以防止這種事情。相反,我從視圖模型自動映射到命令對象,然後從命令處理程序中實際更新實體屬性。我發現從視圖模型直接到實體的自動映射過於混亂和容易出錯,沒有辦法執行業務規則,除非它們在UI層中。 – danludwig

5

我認爲一個動態控制器將有可能是有些過分 - 當你讓一切都通用的,那麼你的觀點一個需要的東西比一個簡單的地圖數據庫更加複雜,會發生什麼 - 你擴大你的「普通視圖控制器'來處理這個?可能會結束here.

你也許應該看看Automapper以消除處理視圖模型的一些重複性質。

http://automapper.codeplex.com/

+0

我現在正在看一下automapper。這可能需要幾天時間,但在我完成一些工作或選擇接受的答案後會回來。同時謝謝你的回答。 –

0

您可以爲對象的EditFor /模型模板,或烏爾基類,不管它是什麼,然後就做一個視圖,它會接受你的模型,它的元數據(與MVC的幫助元數據提供者),並根據動態構建字段。
this post覆蓋藿它可以在MVC2做,但你可以很容易地適應這種技術來MVC 3以及..使用
林這樣的模板在項目MI工作,在那裏我有幾十不同的實體,都有着相同的外觀和感覺。隨着我自己的Metadataprovider的幫助,這也幫助我獲得領域的順序,並且它們應該在每個視圖中可見,我建立了一個視圖,以顯示我所有的實體

+0

感謝您的回答。我正在閱讀這個鏈接,看起來很有趣。雖然automapper似乎更是如此。我可以在一定程度上看到,爲什麼總結控制器可能是太過分了。但我需要做更多的研究。感謝您的回答。 –

+0

tbh,我從來沒有使用automapper,這當然可能是你正確的soltuion ..祝你好運:) – YavgenyP

0

我同意這裏的其他人一個單一的動態控制器來處理你的應用程序中的所有模型和視圖太過分了。還有其他一些方法可以減少控制器中的代碼量。其他答案提到了AutoMapper,這是一個很棒的工具。 AutoMapper的發明者Jimmy Bogard也有一個great video here,其中包含了其他一些可以減少控制器中代碼量的方法。

至於意見,你可以已經有一個觀點,即通過使用EditorTemplates處理所有的控制器。您可以創建一個自定義的EditorTemplate,它將使用反射來檢查模型並相應地呈現輸入字段。這一切都使用「模型元數據」,並有a good post on that by Brad Wilson here

+0

感謝您的答案。我現在正在研究AutoMapper,因爲有很多人推薦它與Brad Wilson站點的鏈接。在完成我的研究後的幾天內,我會接受一個答案。 –