Как создать список выбора из значений базы данных? - PullRequest
5 голосов
/ 04 июля 2011

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

То, что я думал, имеет смысл загружать эти данные вконтроллер и передать его в модель представления, так что я могу использовать SelectListFor<> или что-то еще для генерации списка.Однако это означает, что я должен дублировать загрузку всех списков в методах GET и POST.Другой способ, которым я могу видеть, - передать контекст базы данных в конструктор модели представления и загрузить его список, но тогда возникает еще две проблемы:

1) Должна ли модель представления знать о контексте базы данных?

2) Затем я не могу использовать привязку модели, принимая тип модели представления в качестве аргумента метода, потому что у него нет конструктора без аргументов (если я создаю конструктор без аргументов, у него не будетсписок, если я хочу снова отобразить представление, содержащее форму).

Есть ли лучший способ сделать это?Похоже, что это довольно распространенный сценарий, и любые советы будут оценены.

Ответы [ 4 ]

1 голос
/ 04 июля 2011

Мы обычно реализуем наши поиски через ReferenceDataRepository, который используется внутри контроллеров так же, как и любое другое взаимодействие с репозиторием. Этот репозиторий обычно получает большое количество вызовов для преимущественно статических данных только для чтения, поэтому мы можем реализовать производный CachedReferenceDataRepository поверх этого, используя абстракцию выбранной вами схемы кэширования (Session, AppFabric и т. Д.).

1 голос
/ 04 июля 2011

Почему бы вам не получить базу данных, хранилище или бизнес-правило - как бы вы это ни называли, отправьте обратно IDictionary ???

В этом примере предполагается, что у вас есть список пользователей, вы отправите обратно ключ с его идентификатором, а значение с, скажем, именем + фамилией:

Затем используйте это в представлении....

<%= Html.DropDownListFor(model => model.UserID, new SelectList(Model.AvailableUsers, "Key", "Value",Model.UserID))%>

model.UserID = Key
Model.AvailableUsers = IDictionary<int,string>

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

Передайте этих пользователей непосредственно или альтернативно представлению ViewModel, как в вашем случае, что я и рекомендую

ПРИМЕЧАНИЕ. Вы не будете связывать свой контекст данных с привязкой к списку / модели, это делает вещи слишком сложными.Просто возьмите UserID как выбранного пользователя из списка, а затем в своем сообщении соответственно:

ViewModel:

public class UsersViewModel
{
    public int UserID { get; set; }
    public IDictionary<int,string> AvailableUsers{ get; set; }
}

В вашем сообщении ...

    [HttpPost]
    [ValidateAntiForgeryToken]
    [DemandAuthorization(RoleNames.AdminUser, AlwaysAllowLocalRequests = true)]
    public ActionResult AllUsers(int UserID)
    {
        try
        {
           //save to db or whatever...
            return RedirectToAction("Index", "Users");
        }
        catch (RulesException ex)
        {
            ex.CopyTo(ModelState); //custom validation copied to model state
        }
        var _users= _service.GetUsers();
        return View("AllUsers", new UsersViewModel
        {
            UserID = UserID,
            AvailableUsers = _users
        });

    }
0 голосов
/ 04 июля 2011

Самая большая проблема, которую я вижу при передаче IRepository во ViewModel, заключается в том, что это может легко вызвать проблемы с производительностью - выбор n + 1 настолько естественен в этом случае, что их трудно избежать.Вы хотите иметь как можно меньше переходов к БД для запроса, и IRepository, передаваемый по всем этим многоуровневым моделям представления, просто не поможет.

Вместо этого вы можете ввести фабрику ViewModel, котораяотвечает за создание ViewModels желаемого типа.MyViewModelFactory будет зависеть от IRepository и создаст MyViewModel, что просто DTO.

0 голосов
/ 04 июля 2011

Что ж, на мой взгляд, вам нужно иметь объект контекста или репозитория в вашей модели представления, чтобы оставаться сухим в этом сценарии. Кроме того, также правильно, что ваша viewmodel не должна знать о вашей базе данных. Для решения этой проблемы вы можете сделать так, чтобы конструктор viewmodel принимал интерфейс типа

public Interface IUserRepository
{
    public IEnumerable<User> GetAll();
}

и у вас может быть ваша модель вида как

public class CreateVM
{
    private IUserRepository _repo;
    public CreateVM(IUserRepository repo)
   {
        _repo = repo;
   } 
   public IEnumerable<SelectListItem> AvailableUsers
   {
       get{
            return _repo.GetAll().Where(x=>x.isAvailable).Select(x=>new SelectListinItem{Text = x.UserName, Value = x.UserID});
          } 
   }
}

Последний кусочек головоломки - ваша установка DI. Скажите вашему контейнеру IOC вводить IUserRepository в конструктор вашей модели представления всякий раз, когда она создается. Я не знаю, может ли DI работать, когда связыватель моделей создает экземпляр вашей модели представления, но если это так, то вы, по крайней мере, теоретически. ваша viewmodel не знает ваш репозиторий, а только интерфейс, и ваш список создается в одной точке, поэтому вы тоже сухие.

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