【问题标题】:How can I edit a related object's properties in MVC4?如何在 MVC4 中编辑相关对象的属性?
【发布时间】:2013-10-28 18:28:00
【问题描述】:

我在编辑相关对象的属性时遇到了一些问题。代码如下:

型号:

DocumentLine.cs

/// <summary>
/// States the base implementation for all document lines in a purchasing module.
/// </summary>
public class DocumentLine : Keyed
{
    // ... some other properties

    /// <summary>
    /// Gets or sets the current line's document header.
    /// </summary>
    [Navigation]
    [Display(ResourceType = typeof(Resources.ApplicationResources), Name = "Header")]
    public virtual DocumentHeader Header { get; set; }
}

DocumentHeader.cs

/// <summary>
/// States the base implementation for all document headers in a purchasing module.
/// </summary>
public class DocumentHeader : Keyed
{
    /// <summary>
    /// Gets or sets the current header's document number.
    /// </summary>
    [Required]
    [Display(ResourceType = typeof(Resources.ApplicationResources), Name = "DocumentNumber")]
    public string DocumentNumber { get; set; }

    /// <summary>
    /// Gets or sets the extra cost of the document.
    /// </summary>
    [Display(ResourceType = typeof(Resources.ApplicationResources), Name = "ExtraCost")]
    [RegularExpression(@"^\d*$", ErrorMessageResourceType=typeof(Resources.ApplicationResources), ErrorMessageResourceName= "Exception_ExtraCost_Error")]
    public decimal ExtraCost { get; set; }

    /// <summary>
    /// Gets or sets the vat's extra cost of the document.
    /// </summary>
    [Display(ResourceType = typeof(Resources.ApplicationResources), Name = "ExtraVat")]
    [RegularExpression(@"^\d*$", ErrorMessageResourceType = typeof(Resources.ApplicationResources), ErrorMessageResourceName = "Exception_ExtraVat_Error")]
    public decimal ExtraVat { get; set; }

    /// <summary>
    /// Gets or sets the navigation property to all dependant Document lines.
    /// </summary>
    [Required]
    [Navigation]
    [Display(ResourceType = typeof(Resources.ApplicationResources), Name = "DocumentLines")]
    public virtual ICollection<DocumentLine> DocumentLines { get; set; }
}

查看:

@Html.HiddenFor(model => model.Header.Id, Model.Header != null ? Model.Header.Id : null)
<div class="display-label">
    @Html.DisplayNameFor(model => model.Header.ExtraCost)
</div>
<div class="display-field">
    <input type="text" name="Header.ExtraCost" id="Header.ExtraCost" data-varname="header.extraCost" value="@(Model.Header.ExtraCost)" />
    @Html.ValidationMessageFor(model => model.Header.ExtraCost)
</div>
<div class="display-label">
    @Html.DisplayNameFor(model => model.Header.ExtraVat)
</div>
<div class="display-field">
    <input type="text" name="Header.ExtraVat" id="Header.ExtraVat" data-varname="header.extraVat" value="@(Model.Header.ExtraVat)" />
    @Html.ValidationMessageFor(model => model.Header.ExtraVat)
</div>

我知道 MVC 会跟踪输入的 id 和名称以将值传递给控制器​​,这就是为什么我将隐藏输入设置为 Header.Id 值。此视图正确显示了值,所以我认为问题不在这里。

控制器:

我有一个通用的控制器方法可以编辑,它工作正常,尽管我可能必须针对这种特殊情况重写它。

/// <summary>
/// Handles the POST event for the Edit action, updating an existing TEntity object.
/// </summary>
/// <param name="id">Id of the TEntity object to update.</param>
/// <param name="model">TEntity object with properties updated.</param>
/// <returns>Redirection to the Index action if succeeded, the Edit View otherwise.</returns>
[HttpPost]
public virtual ActionResult Edit(string id, TEntity model)
{
    var request = new RestSharp.RestRequest(Resource + "?id={id}", RestSharp.Method.PUT) { RequestFormat = RestSharp.DataFormat.Json }
        .AddParameter("id", id, RestSharp.ParameterType.UrlSegment)
        .AddBody(model);
    var response = Client.Execute(request);

    // Handle response errors
    HandleResponseErrors(response);

    if (Errors.Length == 0)
        return RedirectToAction("Index");
    else
    {
        ViewBag.Errors = Errors;
        return View(model);
    }
}

主要问题是这段代码不仅没有编辑相关的对象值,而且还将DocumentLine的Header.Id值设置为null。

有什么建议吗?

【问题讨论】:

    标签: c# asp.net-mvc asp.net-mvc-4 razor restsharp


    【解决方案1】:

    问题很可能出现在我的回答的最后一段中,但这里有一些其他提示可以帮助您调试此类问题..

    查看 Google chrome 中的网络选项卡,或下载 Firebug for Firefox 并查看您实际发布到该方法的内容,在该方法上放置一个断点并确保该方法的参数实际上正在获取值。

    删除“标题”。根据您输入的名称和 ID,实际使用 @Html.EditorFor(model => model.ExtraCost) 反而。您还没有为 Edit 视图发布 GET 方法,在此设置断点并确保将实体传递给视图。

    如果你得到这个工作,你只需要使用@Html.HiddenFor(model => model.Id)

    在您看来,Id 将作为 Id 发布,放入您的控制器中称为 id,thsi 不会绑定,所以我怀疑 Id 永远不会真正传递到 ActionResult。

    【讨论】:

    • 我用 Firebug 检查了 POST 调用,它正确地将参数传递给 ActionResult。如果没有“标题”,我将无法使用 EditorFor。因为这是一个继承自 DocumentLine 的 InvoiceLine,它不包含 ExtraCost 和 ExtraVat 的定义。 >_
    • ActionResult中的参数id改成id了吗?
    • 感谢您的回答,但是是的,我已更改它,但它无法正常工作。 Post 参数都是正确的,但它仍在删除Header.Id 属性。如果它没有与 'id' 绑定,我的其余代码将无法工作,所以这似乎不是问题。
    【解决方案2】:

    我不得不修改默认的 RestSharp PUT 方法以强制它首先更新文档标题,然后更新发票行。

    /// PUT api/<controller>/5
    /// <summary>
    /// Upserts a InvoiceLine object and its DocumentHeader to the underlying DataContext
    /// </summary>
    /// <param name="id">Id of the InvoiceLine object.</param>
    /// <param name="value">The InvoiceLine object to upsert.</param>
    /// <returns>An HttpResponseMessage with HttpStatusCode.Ok if everything worked correctly. An exception otherwise.</returns>
    public override HttpResponseMessage Put(string id, [FromBody]InvoiceLine value)
    {
        //If creation date is in UTC format we must change it to local time
        value.DateCreated = value.DateCreated.ToLocalTime();
    
        //update the document header if there is any change
        var header = Database.Set<DocumentHeader>()
            .FirstOrDefault(x => x.Id == value.Header.Id);
    
        if (header != null)
        {
            value.Header.DocumentLines = header.DocumentLines;
            value.Header.DocumentNumber = header.DocumentNumber;
            Database.Entry<DocumentHeader>(header)
                .CurrentValues.SetValues(value.Header);
        }
        else
        {
            Database.Set<DocumentHeader>().Add(value.Header);
        }
    
        // If entity exists, set current values to atomic properties
        // Otherwise, insert as new
        var entity = Database.Set<InvoiceLine>()
            .FirstOrDefault(x => x.Id == id);
    
        if (entity != null)
        {
            Database.Entry<InvoiceLine>(entity)
                .CurrentValues.SetValues(value);
            FixNavigationProperties(ref entity, value);
        }
        else
        {
            FixNavigationProperties(ref value);
            Database.Set<InvoiceLine>().Add(value);
        }
    
        if (value is ISynchronizable)
            (value as ISynchronizable).LastUpdated = DateTime.UtcNow;
    
        // Save changes and handle errors
        SaveChanges();
    
        return new HttpResponseMessage(HttpStatusCode.OK);
    }
    

    这对我有用。希望对您有所帮助。

    【讨论】:

      猜你喜欢
      • 2013-02-20
      • 1970-01-01
      • 1970-01-01
      • 2016-06-12
      • 1970-01-01
      • 2021-08-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多