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

Pil*_*Bob 18 model-binding asp.net-mvc-3

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

我实例化视图模型,然后调用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);
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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

Dis*_*ile 54

使用Exclude属性的Bind属性:

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

    // ...
}
Run Code Online (Sandbox Code Playgroud)

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

您还应该考虑使用TryUpdateModel而不是UpdateModel.您也可以通过将其作为参数传递给构造函数来使其默认模型绑定器:

public ActionResult Create([Bind(Exclude="Id")]SimplifiedCompanyViewModel model)
{
    // ...
}
Run Code Online (Sandbox Code Playgroud)


Des*_*ond 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);
}
Run Code Online (Sandbox Code Playgroud)


Ada*_*SFT 2

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

编辑(添加上面的评论)

DRY 通常适用于逻辑,而不适用于视图模型。一种视图=一种视图模型。使用自动映射器可以轻松地在它们之间进行映射。Jimmy Bogard 对此有一个很棒的属性,使其几乎是自动的 - 即,您创建视图模型,加载您的 Customer 实体,然后在操作方法中返回它。然后,AutpMap 属性会将其转换为 ViewModel。请参阅losechies.com/jimmybogard/2009/06/30/how-we-do-mvc-view-models