2012-05-22 192 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站点的链接。在完成我的研究后的几天内,我会接受一个答案。 –