2012-05-22 4 views
8

Я только начал использовать и влюбился в шаблон дизайна MVC.MVC Уменьшение повторяющегося кода

Мое единственное домашнее животное, похоже, что оно производит много повторяющегося кода. Например.

У меня есть стандартное приложение MVC с моей БД (модели) в одном проекте, отделенное от моих контроллеров/представлений/режимов просмотра в другом, снова отделенное от моих методов тестирования в другом. Все отлично работает.

Модели: Теперь у меня есть куча классных классов 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 контроллеров, которые в то же время выполняют одну и ту же работу)

Затем я хочу сделать то же самое с видами. Так что разные поля могут динамически генерироваться. (Почему 9 или 50 просмотров все выполняют ту же работу). Если представление основано на контроллере, представление должно иметь возможность изменять его свойства.

По существу все, что я хочу сделать, это найти способ сообщить контроллеру читать из режима просмотра X или VM - Y или VM - Z и он должен иметь возможность генерировать свойства, возвращать связанные данные и передавать их к представлению, которое после получения будет генерировать поля с надписями и текстовыми полями.

Я думаю, я хочу знать, есть ли способ сделать это с помощью отражения. Поскольку модели представления представляют собой базовые классы с простыми свойствами. Можно создать класс базового контроллера, который имеет метод для чтения в указанном объекте viewmodel, получать его свойства, читать также связанную таблицу и сопоставлять поля в этой таблице со свойствами в классе. Наконец, можно записать в таблицу из таблицы для отображения. Затем представление может быть сгенерировано автоматически на основе этого с использованием какой-либо бритвы, C# или javascript.

Любые приступы, если это возможно или нет, приветствуются.

+0

Почему вы смешиваете шаблон MVC и MVVM? Я предполагаю, что я спрашиваю, для чего вам нужен ViewModel и не просто пройти модель? – Brunner

+0

@Brunner - Ну во-первых, его способ, которым я был показан, и я не знаю, как это сделать напрямую (я относительно новичок в MVC). Во-вторых, мой работодатель хочет, чтобы это было сделано так. Наконец, когда я работаю над своими собственными проектами, я делаю это так, потому что мне не нравится иметь фактическую БД как часть проекта, как показано на многих примерах, и автоматически генерировать или регенерировать. Существует очень мало практических примеров, показывающих, как подключиться к реальной базе данных. Если вы знаете что-нибудь, я бы действительно использовал ссылки на них. Спасибо за ваш ответ. –

+0

Я не уверен, что вы подразумеваете под «настоящими живыми dbs», но вы можете посмотреть на POCOs в сочетании с EF (например, Code-First) - это более или менее то, что у вас уже есть, просто аккуратно упаковано. Я также не уверен, что вы подразумеваете, не имея фактического БД в проекте, поскольку вы, например, можете сделать «return new View (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) следует использовать только для одностороннего отображения, его не рекомендуется переходить с почтового метода обратно на объект. Он работал бы в некоторых случаях, но в других случаях разваливается на другие, скажем, структура сущности, поскольку свойства не имеют установленного им «измененного» флага, но сам объект делает это, и это не приводит к изменениям, возвращающимся к db. Просто фью, чтобы кто-нибудь еще читал. –

+0

@AdamTuliper - я использовал AutoMapper с EF без проблем. Все, что делает AutoMapper, это вызов свойств, которые не отличаются от выполнения вручную в коде. Не могли бы вы рассказать о проблемах, которые вы испытали? –

+0

Я использую AutoMapper для двухстороннего сопоставления, но я больше не привязываю ViewModels к объектам. У наших сущностей теперь есть «защищенные внутренние множества», чтобы предотвратить подобные вещи. Вместо этого я автоматически перехожу от viewmodel к объекту команды, а затем выполняю фактическое обновление свойств сущности из обработчика команд. Я обнаружил, что автоматическое форматирование из viewmodels прямо к объектам было слишком грязным и подверженным ошибкам, без возможности применения бизнес-правил, если они не были в слое пользовательского интерфейса. – danludwig

5

Я думаю, что один динамический контроллер, возможно, будет слишком большим шагом - что происходит, когда вы делаете все родовым, а затем одно из ваших представлений требует чего-то более сложного, чем простая карта для базы данных - расширяете ли вы свой общий вид контроллер ", чтобы справиться с этим? Может закончиться here.

Возможно, вы должны взглянуть на Automapper, чтобы устранить некоторые повторяющиеся особенности работы с вашими режимами просмотра.

http://automapper.codeplex.com/

+0

Я сейчас смотрю на automapper. Это может занять несколько дней, но я вернусь после того, как сделаю немного или решар, чтобы выбрать принятый ответ. В то же время спасибо за ваш ответ. –

0

Можно создать шаблоны EditFor/Модель для объекта или ур базового класса, какой бы она есть, а потом просто сделать один вид, который будет принимать вашу модель, метаданные (с помощью MVC метадатчики), и динамически строить поля.
this post охватывает HWO это может быть сделано в MVC2, но и можно легко адаптировать эту технику MVC 3, а ..
Im помощью такого шаблона в проекте ми работать, где у меня есть несколько десятков различных организаций , все обмениваются одинаковым внешним видом. С помощью своего собственного Метадатапровайдера, который также помогает мне получить заказ на поля, и они должны быть видимыми в каждом представлении, я построил один вид, чтобы показать все мои объекты.

+0

Спасибо за ответ. Я в процессе чтения этой ссылки, и это кажется интересным. Хотя automapper кажется еще более. В какой-то степени я вижу, почему обобщение контроллера может быть шагом слишком далеко. Но мне нужно сделать больше исследований. Спасибо за Ваш ответ. –

+0

tbh, я никогда не использовал automapper, и это, конечно, может быть правильным soltuion для вас .. удачи :) – YavgenyP

0

Я согласен с другими здесь в том, что один динамический контроллер для обработки всех моделей и представлений в вашем приложении заходит слишком далеко. Существуют и другие способы уменьшения количества кода в контроллерах. Другие ответы здесь упоминали AutoMapper, который является отличным инструментом. У изобретателя AutoMapper, Джимми Богарда, также есть great video here, который включает в себя другие вещи, которые вы можете сделать, чтобы уменьшить количество кода в ваших контроллерах.

Что касается представлений, у вас уже может быть один вид, который обрабатывает все ваши контроллеры с помощью EditorTemplates. Вы можете создать настраиваемый шаблон EditorTemplate, который будет использовать отражение, чтобы исследовать модель и соответствующим образом отобразить поля ввода. Все это использует «метаданные модели», и есть a good post on that by Brad Wilson here.

+0

Спасибо за ответ. Сейчас я просматриваю AutoMapper, потому что многие люди рекомендовали его вместе со ссылкой на сайт Brad Wilson. Я приму ответ в течение нескольких дней после того, как закончу свое исследование. –

Смежные вопросы