在调用UpdateModel()时如何从绑定中排除属性?

时间:2011-11-30 20:35:06

标签: asp.net-mvc-3 model-binding

我有一个视图模型发送到我的控制器的编辑操作。 ViewModel包含对EntityObjects的引用。 (是的,我很喜欢它,不需要复制视图模型中的所有实体属性)。

我实例化视图模型,然后调用UpdateModel。我得到一个属性为“null”的错误,这很好,因为它是一个相关的模型。我试图在模型绑定期间排除属性绑定。在调试它时,我在实体中看到模型绑定器试图将属性的值设置为null。

这是我的编辑操作:

var model = new SimplifiedCompanyViewModel(id);

var excludeProperties = new string[] { 
   "Entity.RetainedEarningsAccount.AccountNo"
   ,"Property.DiscountEarnedAccount.ExpenseCodeValue"
   ,"Entity.EntityAlternate.EntityID"
   ,"Property.BankAccount.BankAccountID"
   ,"Entity.PLSummaryAccount.AccountNo"
   ,"Property.RefundBank.BankAccountID"
   ,"Company.Transmitter.TCC"
};

try
{
    UpdateModel<SimplifiedCompanyViewModel>(model, String.Empty, null, excludeProperties);

    if (ModelState.IsValid)
    {
       //db.SaveChanges();
    }
       return RedirectToAction("Index");
}
catch
{
    return View(model);
}

我已经看了一些关于指定“前缀”的其他问题,但我不认为这是问题,因为我告诉它绑定到viewmodel实例而不仅仅是实体对象。

我是否正确排除了这些属性?奇怪的是,这件事似乎只发生了。我怀疑这可能是一个问题,实际上没有与我的实体相关的退款银行。但是我有其他相关的项目不存在,并没有看到相同的问题。

更多信息...因为我告诉我模型设计不好。

本公司与BankAccount有关。公司视图显示当前相关的BankAccount.BankAccountId,并且BankAccount.Key有一个隐藏字段。我使用jQueryUI自动完成功能提供显示BankAccount.BankAccountId的银行帐户下拉列表,当选择一个时,jQuery代码会更改隐藏字段以获得正确的Key值。因此,当发布此消息时,我不希望修改当前的银行账户BankAccountID,因此我希望它跳过绑定该字段。

如果我在模型中排除BankAccountId,那么在BankAccount编辑视图中,用户永远无法更改BankAccountId,因为它不会被绑定。我不确定这表明模型设计不佳。

4 个答案:

答案 0 :(得分:54)

使用Exclude属性的Bind属性:

[Bind(Exclude="Id,SomeOtherProperty")]
public class SimplifiedCompanyViewModel
{
    public int Id { get; set; }

    // ...
}

这是System.Web.Mvc命名空间的一部分。它需要以逗号分隔的属性名列表,以便在绑定时排除。

另外,您应该考虑使用TryUpdateModel而不是UpdateModel。你也可以让默认的模型绑定器通过将它作为参数传递给构造函数来解决它:

public ActionResult Create([Bind(Exclude="Id")]SimplifiedCompanyViewModel model)
{
    // ...
}

答案 1 :(得分:6)

我想出的一个非常简单的解决方案。

 try
{
   UpdateModel<SimplifiedCompanyViewModel>(model, String.Empty, null, excludeProperties);
   ModelState.Remove("Entity.RetainedEarningsAccount.AccountNo");
   ModelState.Remove("Property.DiscountEarnedAccount.ExpenseCodeValue");
   ModelState.Remove("Entity.EntityAlternate.EntityID");
   ModelState.Remove("Property.BankAccount.BankAccountID");
   ModelState.Remove("Entity.PLSummaryAccount.AccountNo");
   ModelState.Remove("Property.RefundBank.BankAccountID");
   ModelState.Remove("ompany.Transmitter.TCC");

    if (ModelState.IsValid)
    {
       //db.SaveChanges();
    }
       return RedirectToAction("Index");
}
catch
{
    return View(model);
}

答案 2 :(得分:2)

尝试Exclude属性 我承认我从未使用过它。

[Exclude]
public Entity Name {get; set;}

答案 3 :(得分:2)

此处的另一个选项是在视图中不包含此属性,并且不会绑定。是的 - 如果有人在页面上创建它,你仍然可以使用模型注入,但这是另一种选择。 MVC中的默认模板将创建您的EditorFor等作为单独的项目,因此您可以删除它们。这会阻止您使用带有EditorForModel的单行视图编辑器,但模板不会以任何方式为您生成。

编辑(添加以上评论)

DRY通常适用于逻辑,而不适用于查看模型。一个视图=一个视图模型。使用automapper可以轻松地在它们之间进行映射Jimmy Bogard有一个很好的属性使它几乎是自动的 - 即你创建视图模型,例如加载你的Customer实体,然后在action方法中返回它。然后,AutpMap属性将其转换为ViewModel。见lostechies.com/jimmybogard/2009/06/30/how-we-do-mvc-view-models