Куда должен идти код для построения моделей представлений? - PullRequest
5 голосов
/ 17 марта 2012

При создании модели представления в MVC3 asp.net, куда должен идти код для создания экземпляров объектов этой модели представления?Я делаю это в основном в контроллере прямо сейчас, за исключением кода для запроса к базе данных.Вот пример в коде:

Просмотр модели:

public class WorkListVM
{
    //list for employees
    [Display(Name = "Select A Employee")]
    [Required]
    public int? EmployeeId { get; set; }
    public GenericSelectList EmployeeList { get; set; }
}

Код контроллера:

        //build view model
        var vm = new WorkListVM();

        //build employee list
        vm.EmployeeList = new GenericSelectList(0,"-- Select Employee --");
        var employees = new List<Employee>();
        using (var gr = new GenericRepo<Employee>())
        {
            employees = gr.Get().ToList();
        }
        foreach(var employee in employees)
        {
            var gl = new GenericListItem();
            gl.Id = employee.EmployeeId;
            gl.DisplayFields = employee.FirstName + " " + employee.LastName;
            vm.EmployeeList.Values.Add(gl);
        }

Общий список выбора - это простой класс для хранения данных, которые идутв помощнике @html.dropdownfor х SelectList.Я строю эти списки выбора, а также строю аналогичные конфигурации данных для моделей представления внутри кода контроллера.Контроллер, на котором размещен этот код, имеет в общей сложности 109 строк кода, поэтому он не слишком большой или неуправляемый.Однако я всегда стремлюсь уменьшить избыточность, и иногда код в //build employee list заканчивается копированием и вставкой (тьфу, я ненавижу копировать вставку) в другие контроллеры.

Есть ли лучшее место для этого кода?Должен ли я использовать фабричный шаблон для создания данных для этих списков выбора / других объектов данных представления?

РЕДАКТИРОВАТЬ

Спасибо за вашу помощь.Вот что я в итоге сделал.В итоге я создал метод внутри класса общего списка выбора, очень похожий на .ToSelectList (...), предложенный Ричардом и Джесси:

    public class GenericSelectList
{
    public List<GenericListItem> Values { get; set; }
    public int StartValue { get; set; }
    public string Message { get; set; }

    public GenericSelectList(int StartValue = 0, string Message = "select")
    {
        Values = new List<GenericListItem>();
        this.StartValue = StartValue;
        this.Message = Message;
    }

    public void BuildValues<T>(List<T> items, Func<T, int> value, Func<T, string> text) where T : class
    {
        this.Values = items.Select(f => new GenericListItem()
        {
            Id = value(f),
            DisplayFields = text(f)
        }).ToList();
    }
}

Ответы [ 4 ]

2 голосов
/ 17 марта 2012

Если бизнес-логика, которая входит в создание модели представления, довольно сложна, я обычно извлекаю ее в вспомогательный метод, который я могу протестировать независимо от контроллера.

Однако, кроме этого, ваше создание модели представления прекрасно в контроллере, как оно есть.Как уже отмечалось, как создание списка выбора можно сделать намного проще (не говоря уже о возможности многократного использования).

Вот расширение ToSelectList IEnumerable вместе с примером использования:

public static List<SelectListItem> ToSelectList<T>( this IEnumerable<T> enumerable, Func<T, string> value, Func<T, string> text, string defaultOption)
{
    var items = enumerable.Select(f => new SelectListItem()
                                          {
                                              Text = text(f) ,
                                              Value = value(f)
                                          }).ToList();

    if (!string.IsNullOrEmpty(defaultOption))
    {
                    items.Insert(0, new SelectListItem()
                        {
                            Text = defaultOption,
                            Value = string.Empty
                        });
    }

    return items;
}

В вашей модели представления вы можете добавить свойство следующим образом:

IEnumerable<SelectListItem> Employees { get; set; }

В вашем контроллере (я предполагаю, что ваше хранилище возвращает IEnumberable):

var employees = new IEnumerable<Employee>();
using (var gr = new GenericRepo<Employee>())
{
    employees = gr.Get();
}

vm.Employees = employees.ToSelectList(x=>x.FirstName + " " + x.LastName, x=>x.Id, "-- Select Employee --")

Изатем, чтобы настроить выпадающий список в представлении, он будет выглядеть примерно так:

@Html.DropDownListFor(model => model.EmployeeId, Model.employees)
2 голосов
/ 17 марта 2012

1 - Вы можете добавить метод расширения к IEnumerable<Employee> или IQueryable<Employee>, который возвращает ваш GenericSelectList.Преимущества - вы можете повторно использовать любую коллекцию сотрудников, то есть отфильтрованный список, и довольно приятный синтаксис вызова;Вы можете настроить, как список выбора формируется на индивидуальной основе.Недостатки - вам придется написать один из этих методов для каждого типа.

2 - Вы можете изменить этот метод расширения для работы с универсальным, который работает против IEnumerable<T> и производит GenericSetList на основеExpression входов.Преимущества - Ваш метод теперь действительно универсальный, то есть напишите один раз и используйте повторно.Вы можете сделать это таким образом, чтобы она объединялась с 1, чтобы ваша функция «1 на класс» использовала обобщение для сохранения дублирования.Недостатки - предполагается удобство в использовании выражений и т. П.

3 - У вас могут быть фабричные методы, которые возвращают ViewModels.

Эти вещи также могут работать в комбинации и должны помочь удалить copy /вставьте код и продвигайте повторное использование и тестируемость.

Правка - вот один из способов, которым нет.2 можно реализовать (в VB, но перевод на C # тривиален).Затем я бы добавил перегрузки для полезных перестановок входных данных.

Imports System.Runtime.CompilerServices
Imports System.Linq.Expressions

Module IQueryableExtensions

    <Extension()>
    Public Function ToSelectList(Of T)(source As IEnumerable(Of T), nameExpression As Expression(Of Func(Of T, String)), valueExpression As Expression(Of Func(Of T, String)), selectedExpression As Expression(Of Func(Of T, Boolean)), additionalItems As IEnumerable(Of SelectListItem)) As IEnumerable(Of SelectListItem)
        Return additionalItems.Union(
            source.Select(Function(x) New SelectListItem With {
                              .Text = nameExpression.Compile.Invoke(x),
                              .Value = valueExpression.Compile.Invoke(x),
                              .Selected = selectedExpression.Compile.Invoke(x)
                          }
                      )
                  )
    End Function

End Module

Пример использования:

    Dim People As New List(Of Person) From {New Person With {.Name = "Richard", .ID = 1}}

    Dim sl = People.ToSelectList(Function(p) p.Name,
                                 Function(p) p.ID,
                                 Function(p) p.ID = 1,
                                 {New SelectListItem With {.Value = 0,
                                                           .Text = "Please Select A Person"}})
2 голосов
/ 17 марта 2012

Если ваша цель - избежать избыточного кода, вы должны извлечь общие части в вспомогательные методы. В самой простой форме вы можете использовать статические методы для этого.

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

Вы можете структурировать свой код любым удобным вам способом. Используйте стандартные методы, чтобы справиться со сложностью, такие как вспомогательные методы и (экономно) абстракции. Нет необходимости идти сложным, когда достаточно простого.

1 голос
/ 17 марта 2012

Я не знаю, является ли это правильным способом, но я использую его, и это помогает мне контролировать все.

контроллер в моих глазах делает такие вещи, как обновление сеансов, куки и затем возвращаетПосмотреть.Я никогда не использую его для сортировки каких-либо данных или создания объектов для отправки в представление.

(я могу обмануть, если это один на один вкладыш: p)

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

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

Мартын

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...