【问题标题】:Create View for ViewModel post returns ViewModel with empty foreign key properties为 ViewModel 创建视图帖子返回具有空外键属性的 ViewModel
【发布时间】:2012-07-06 16:16:04
【问题描述】:

我正在用 ASP.NET MVC3 开发一个 Web 应用程序(我的第一个),意思是为我工作的工程公司跟踪数据处理步骤。

以下是一些领域模型:

数据集:

Partial Public MustInherit Class Dataset
    Public Property DatasetID As System.Guid
    Public Property Name As String

    Public Overridable Property ProcessDatasets As ICollection(Of ProcessDataset) = New HashSet(Of ProcessDataset)
    Public Overridable Property DeliveryBatches As ICollection(Of DeliveryBatch) = New HashSet(Of DeliveryBatch)

End Class

流程:

Partial Public Class Process
    Public Property ProcessID As System.Guid
    Public Property Name As String
    Public Property Type As String
    Public Property Description As String
    Public Property SOP As String
    Public Property ProcessOrder As Nullable(Of Integer)

    Public Overridable Property ProcessDatasets As ICollection(Of ProcessDataset) = New HashSet(Of ProcessDataset)

End Class

ProcessDataset:(属性连接表)

Partial Public Class ProcessDataset
    Public Property ProcessID As System.Guid
    Public Property DatasetID As System.Guid
    Public Property OwnerID As Nullable(Of System.Guid)
    Public Property Started As Nullable(Of Date)
    Public Property Completed As Nullable(Of Date)

    Public Overridable Property Dataset As Dataset
    Public Overridable Property Process As Process
    Public Overridable Property ProcessOwner As ProcessOwner

End Class

我的目标是从数据集的索引或详细信息视图中选择 1 个或多个数据集(使用域模型),然后单击指向 Add New Process to Dataset(s) 的链接,这将打开所需的创建视图。 Create 视图创建的任何 ProcessDatasets 都会自动引用选定的 Datasets,而无需用户从列表中选择它们。

下面是我为 ProcessDataset 创建的 ViewModel。

ProcessStatusDataset:

Public Class ProcessStatusDataset

    Public Property ProcessDataset As ProcessDataset
    Public Property Datasets As IEnumerable(Of Dataset)

End Class

ProcessDatasetController 中的控制器方法:

'
' GET: /ProcessDataset/Create

Function CreateProcessStatus(id As Guid) As ViewResult
    Dim processStatus As New ProcessStatusDataset
    processStatus.Datasets = db.Datasets.Where(Function(d) d.DatasetID = id)
    ViewBag.ProcessID = New SelectList(db.Processes, "ProcessID", "Name")
    ViewBag.OwnerID = New SelectList(db.ProcessOwners, "ProcessOwnerID", "Name")
    Return View(processStatus)
End Function

'
' POST: /ProcessDataset/Create

<HttpPost()>
Function CreateProcessStatus(processstatusdataset As ProcessStatusDataset) As ActionResult
    If ModelState.IsValid Then
        For Each dataset In processstatusdataset.Datasets
            Dim processdataset As New ProcessDataset
            processdataset.ProcessID = processstatusdataset.ProcessDataset.ProcessID
            processdataset.OwnerID = processstatusdataset.ProcessDataset.OwnerID
            processdataset.Completed = processstatusdataset.ProcessDataset.Completed
            processdataset.Started = processstatusdataset.ProcessDataset.Started
            processdataset.DatasetID = dataset.DatasetID
            db.ProcessDatasets.Add(processdataset)
        Next
        db.SaveChanges()
        Return RedirectToAction("Index")
    End If

    ViewBag.ProcessID = New SelectList(db.Processes, "ProcessID", "Name", processstatusdataset.ProcessDataset.ProcessID)
    ViewBag.OwnerID = New SelectList(db.ProcessOwners, "ProcessOwnerID", "Name", processstatusdataset.ProcessDataset.OwnerID)
    Return View(processstatusdataset)

CreateProcessStatus 视图:

@ModelType ProductionDataTrackingMVC.ProcessStatusDataset
@Code
    ViewData("Title") = "Add New Process to Datasets"
End Code
<h2>
    Add New Process to Datasets</h2>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
@Using Html.BeginForm("CreateProcessStatus","ProcessDataset")
    @Html.ValidationSummary(True)
    @<fieldset>
        <legend>Process Status</legend>
        <div class="editor-label">
            @Html.LabelForPascalCase(Function(model) model.ProcessDataset.Process):
        </div>
        <div class="editor-field">
            @Html.DropDownList("ProcessID", String.Empty)
            @Html.ValidationMessageFor(Function(model) model.ProcessDataset.ProcessID)
        </div>
        <div class="editor-label">
            @Html.LabelForPascalCase(Function(model) model.ProcessDataset.ProcessOwner):
        </div>
        <div class="editor-field">
            @Html.DropDownList("OwnerID", String.Empty)
            @Html.ValidationMessageFor(Function(model) model.ProcessDataset.OwnerID)
        </div>
        <div class="editor-label">
            @Html.LabelForPascalCase(Function(model) model.ProcessDataset.Started):
        </div>
        <div class="editor-field">
            @Html.EditorFor(Function(model) model.ProcessDataset.Started)
            @Html.ValidationMessageFor(Function(model) model.ProcessDataset.Started)
        </div>
        <div class="editor-label">
            @Html.LabelForPascalCase(Function(model) model.ProcessDataset.Completed):
        </div>
        <div class="editor-field">
            @Html.EditorFor(Function(model) model.ProcessDataset.Completed)
            @Html.ValidationMessageFor(Function(model) model.ProcessDataset.Completed)
        </div>
        <br />
        <div>
            <table>
                <tr>
                    <th>
                        Dataset Type
                    </th>
                    <th>
                        @Html.LabelForPascalCase(Function(model) model.Datasets.FirstOrDefault().Name)
                    </th>
                </tr>
    @For Each item In Model.Datasets
        Dim currentItem = item
                @<tr>
                    <td>
                        @currentItem.GetType().BaseType.Name
                    </td>
                    <td>
                        @Html.DisplayFor(Function(modelItem) currentItem.Name)
                    </td>
                </tr>
    Next
            </table>
        </div>
        <p>
            <input type="submit" value="Add New Process Status" />
        </p>
    </fieldset>
End Using
<div>
    @Html.ActionLink("Back to Process Status Datasets List", "Index")
</div>

此时,传递给CreateProcessStatus POST 方法的ProcessStatusDataset 始终带有空白Guid,其中应该有ProcessOwner 的ID。 Datasets 属性也是 Nothing

当我查看渲染页面的来源时,我看到了:

<form action="/ProcessDataset/CreateProcessStatus/e29bc119-b8c2-4ac5-9ce7-c9780673c193" method="post">

链接末尾的 Guid 是在 Dataset 详细信息视图中选择的单个 Dataset 的 ID。

谁能指出我正确的方向。我一直在搜索谷歌,但没有成功。

【问题讨论】:

    标签: asp.net asp.net-mvc-3 post mvvm viewmodel


    【解决方案1】:

    下拉菜单

    我认为这行不通:

    ...

    @Html.DropDownList("ProcessID", String.Empty)
    

    ...

    相反,您应该尝试以下方法:

    ...

    @{
        Dim processes = DirectCast(ViewBag.Processes, SelectList);
    }
    
    @Html.DropDownListFor(Function(model) model.ProcessDataset.ProcessId, processes, "Select Process")
    

    ...

    'remember to set this on the post too, in case of returning the same view.
    ViewBag.Processes = New SelectList(db.Processes, "ProcessID", "Name")                   
    

    ...

    这应该让模型绑定器(如果您不知道这个概念,您可能想用谷歌搜索)发挥它的魔力。否则,只需将 HttpPost 操作方法的返回类型更改为 FormCollection 并检查键以检查您从帖子中返回的内容。

    数据集问题

    我认为您没有设置任何 html 表单字段来期望在您的帖子中看到某些内容。

    【讨论】:

    • 我不确定我是否理解您在这里的建议。您在回答的数据集问题部分是什么意思?
    • 您说在您的帖子操作中Datasets 属性是Nothing,这是因为没有任何字段可以在您的html 表单中存储此类信息。您是否检查了我提到的FormCollection 方法,这可能有助于了解发布结果的情况。
    • 我明白你在说什么。我假设因为我将模型传递到具有数据集的视图中,所以视图会将相同的模型与添加的数据一起传递回来。看来视图创建了一个新模型来传回?我将如何使数据集与发布回控制器的模型保持一致?顺便说一句,您的下拉建议有效,谢谢。
    • 在您的情况下,我会使用 DatasetId 设置一个隐藏输入,因为它似乎是您在帖子中需要的唯一属性。如果你编码正确,它应该只是你视图上添加隐藏字段的一行,你的 Post Action 应该像现在一样工作。我把这个留给你兄弟,你已经接近了!阅读模型绑定器,这很重要。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-12
    相关资源
    最近更新 更多