0

我的问题与此堆栈溢出问题中提出的情况基本相同,我发现自己想从数据库中加载现有的有效模型版本,并更新其中的一部分,因为某些字段子集暴露在我的网络表格。

无论如何我可以让模型绑定过程保证我的 ID 属性将首先被绑定吗?

如果我能保证这一点,那么,在我的 ViewModel 的 ID 属性的设置器中,我可以触发“加载”,以便最初从数据库(或 WCF 服务..或 Xml 文件..或其他选择的存储库),然后当 MVC 完成它的模型绑定过程时,从 FORM 提交的其余属性巧妙地合并到对象中。

然后,我的 IValidatableObject.Validate 方法逻辑会很好地告诉我结果对象是否仍然有效......等等......

在我看来,必须在我有两个模型实例(knownValidDomainModelInstanceFromStorage,postedPartialViewModelInstanceFromForm)的地方编写管道,然后手动映射所需的属性是重复 MVC 已经处理的事情......如果我只能控制身份的绑定顺序。


编辑 - 我发现属性绑定顺序可以使用自定义活页夹进行操作。非常简单地。阅读我在下面发布的答案。仍然欢迎您的反馈或意见。

4

1 回答 1

0

好的,在阅读了如何自定义默认模型绑定器之后,我认为这段代码可以完成对属性进行排序的技巧,并且每次都会给我所需的绑定顺序。基本上允许我首先绑定标识属性(从而允许我让我的视图模型触发“加载”),从而允许模型绑定过程的其余部分基本上作为合并运行!

''' <summary>
''' A derivative of the DefaultModelBinder that ensures that desired properties are put first in the binding order.
''' </summary>
''' <remarks>
''' When view models can reliably expect a bind of their key identity properties first, they can then be designed trigger a load action 
''' from their repository. This allows the remainder of the binding process to function as property merge.
''' </remarks>
Public Class BindIdFirstModelBinder
        Inherits DefaultModelBinder

    Private commonIdPropertyNames As String() = {"Id"}
    Private sortedPropertyCollection As ComponentModel.PropertyDescriptorCollection

    Public Sub New()
        MyBase.New()
    End Sub

    ''' <summary>
    ''' Use this constructor to declare specific properties to look for and move to top of binding order.
    ''' </summary>
    ''' <param name="propertyNames"></param>
    ''' <remarks></remarks>
    Public Sub New(propertyNames As String())
        MyBase.New()
        commonIdPropertyNames = propertyNames
    End Sub

    Protected Overrides Function GetModelProperties(controllerContext As ControllerContext, bindingContext As ModelBindingContext) As ComponentModel.PropertyDescriptorCollection
        Dim rawCollection = MyBase.GetModelProperties(controllerContext, bindingContext)

        Me.sortedPropertyCollection = rawCollection.Sort(commonIdPropertyNames)

        Return sortedPropertyCollection
    End Function

End Class

然后,我可以注册它来代替我的 DefaultModelBinder,并提供我希望“浮动”到 ModelBinding 进程顶部的最常见的属性名称......

    Sub Application_Start()

            RouteConfig.RegisterRoutes(RouteTable.Routes)
            BundleConfig.RegisterBundles(BundleTable.Bundles)
            ' etc... other standard config stuff omitted...
            ' override default model binder:
            ModelBinders.Binders.DefaultBinder = New BindIdFirstModelBinder({"Id", "WorkOrderId", "CustomerId"})
    End Sub
于 2013-10-10T13:27:22.540 回答