5

我很难想出最好的方法是在控制器操作中重新创建数据库对象。

我想使用 ModelBinders,因此在我的操作中,我可以通过参数访问对象,而不必重复代码以根据标识符参数从数据库中获取对象。所以我正在考虑有一个 ModelBinder 执行对数据访问层的调用以获取原始对象(或者如果它在数据库中不存在则创建一个新对象),然后将任何属性绑定到数据库对象以更新它。但是我读到 ModelBinders 不应该进行数据库查询(本文的第一条评论)。

如果 ModelBinder 不应该执行数据库查询(所以只使用 DefaultModelBinder),那么具有其他 db 对象属性的数据库对象呢?这些永远不会被分配。

在用户编辑对象后保存对象(视图中可编辑 1 或 2 个属性)ModelBinded 对象将丢失数据,因此按原样保存会导致数据库中的数据被无效值覆盖,或者不是 - NULL 约束失败。

那么,从与从视图回发的表单数据绑定的数据库中获取控制器操作中的对象的最佳方法是什么?

注意我使用 NHibernate。

4

4 回答 4

4

我从数据库中获取模型对象,然后在对象上使用 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");
}
于 2009-02-05T00:45:34.980 回答
2

不幸的是,您无法控制模型绑定器的构建,因此您无法注入任何存储库实现。

可以直接联系服务定位器以拉入您的存储库并获取项目:

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);                                    
    }       
}

如果您可以使用提供类 ID 的基类或接口,您甚至可以使所有实体都使用此功能。

您必须在 Global.asax 中进行设置:

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

然后你可以这样做:

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

    _repository.Save(product);
}
于 2009-02-05T15:09:01.740 回答
0

首先声明,我不建议从 ModelBinders 访问数据库,因为从关注点分离的角度来看,ModelBinders 应该只负责解释客户端请求,显然数据库不是。
如果您不想重复自己(DRY),请使用存储库/服务但是如果您真的想那样做,那么

在 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;
    }
}

遵循 Ben Scheirman 的进一步指示

于 2014-11-24T21:46:58.787 回答
-1

您实际上不必访问数据库。简单地设置对象的 ID 就足以建立关系,但要注意你的级联。确保您的级联设置不会更新相关对象,因为它会清除值。

于 2009-02-06T13:53:28.803 回答