Привязка моделей объектов базы данных в ASPNET MVC - PullRequest
5 голосов
/ 05 февраля 2009

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

Я хочу использовать ModelBinder, чтобы в моем действии я имел доступ к объекту через параметр, а не повторял код, чтобы получить объект из базы данных на основе параметра идентификатора. Поэтому я думал о том, чтобы иметь ModelBinder, который выполняет вызов уровня доступа к данным для получения исходного объекта (или создает новый, если его нет в базе данных), а затем привязывает любые свойства к объекту базы данных, чтобы обновить его. Однако я читал, что ModelBinder не должен делать запросы к базе данных (первый комментарий к этой статье ).

Если ModelBinder не должен выполнять запрос к базе данных (так, просто используя DefaultModelBinder), то как насчет объектов базы данных, которые имеют свойства, которые являются другими объектами БД? Они никогда не будут назначены.

Сохранение объекта после того, как пользователь отредактировал его (1 или 2 свойства доступны для редактирования в объекте), объекту ModelBinded будут отсутствовать данные, поэтому при сохранении его в том виде, как он есть, данные в базе данных будут перезаписаны недопустимыми значениями или ограничения NOT-NULL не выполняются.

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

Обратите внимание, что я использую NHibernate.

Ответы [ 4 ]

4 голосов
/ 05 февраля 2009

Я получаю объект модели из базы данных, затем использую UpdateModel (или TryUpdateModel) для объекта, чтобы обновить значения из параметров формы.

public ActionResult Update( int id )
{
     DataContext dc = new DataContext();
     MyModel model = dc.MyModels.Where( m => m.ID == id ).SingleOrDefault();

     string[] whitelist = new string[] { "Name", "Property1", "Property2" };

     if (!TryUpdateModel( model, whitelist )) {
        ... model error handling...
        return View("Edit");
     }

     ViewData.Model = model;

     return View("Show");
}
2 голосов
/ 05 февраля 2009

К сожалению, у вас нет контроля над созданием подшивки модели, поэтому вы не можете внедрить какую-либо реализацию репозитория.

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

public class ProductBinder : DefaultModelBinder
{
    protected override object CreateModel(ControllerContext controllerContext, 
        ModelBindingContext bindingContext, Type modelType)
    {
        if(modelType != typeof(Product))
            return null;

        var form = controllerContext.HttpContext.Request.Form;
        int id = Int32.Parse(form["Id"]);
        if(id == 0)
            return base.CreateModel(controllerContext, bindingContext, modelType);

        IProductRepository repository = ServiceLocator.Resolve<IProductRepository>();

        return repository.Fetch(id);                                    
    }       
}

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

Вам нужно будет настроить это в Global.asax:

ModelBinders.Binders.Add(typeof(Product), new ProductBinder());

и тогда вы можете сделать это:

public ActionResult Save([Bind] Product product)
{
    ....

    _repository.Save(product);
}
0 голосов
/ 25 ноября 2014

Позвольте мне сначала заявить, что я не рекомендую обращаться к базе данных из ModelBinders, поскольку с точки зрения разделения проблем ModelBinder должен отвечать только за интерпретацию клиентского запроса, очевидно, база данных не является.
Если вы не хотите повторять себя (СУХОЙ), используйте репозитории / сервисы Однако, если вы действительно хотите сделать это так, то

В global.asax.cs Зарегистрировать пользовательский MyModelBinderProvider в MVC

ModelBinderProviders.BinderProviders.Add(new EntityModelBinderProvider 
{ 
     ConnectionString = "my connection string"
));

Создайте пользовательский ModelBinderProvider, содержащий параметры базы данных

public class EntityBinderProvider: IModelBinderProvider
{
    public string ConnectionString { get; set; }

    public IModelBinder GetBinder(Type modelType)
    {
        if (Is known entity)
            return new EntityBinder(ConnectionString);
        else
            return null;
    }
}

Следуйте дальнейшим инструкциям Бена Шейрмана

0 голосов
/ 06 февраля 2009

На самом деле вам не нужно попадать в базу данных. Простого задания идентификатора объектов будет достаточно, чтобы установить отношения, но следите за своими каскадами. Убедитесь, что ваши настройки каскада не обновят связанный объект, поскольку он очистит значения.

...