【问题标题】:Correct way to update related field for 1-to-many relation为一对多关系更新相关字段的正确方法
【发布时间】:2012-09-21 06:14:53
【问题描述】:

Issuer 具有作为相关字段的 KeyEntity。我的代码有效,但我认为除了从数据库加载实体之外,必须有更好的方法来更新相关字段。 ViewModeling 和模板应该有问题...在此先感谢。

OpViewModel

public class OpViewModel
{   
    public Connect.Models.Issuer Issuer { get; set; }
    public IEnumerable<SelectListItem> KeyEntities { get; set; }

    public OpViewModel() { } 
    public OpViewModel(Connect.Models.Issuer issuer, 
                        IEnumerable<Jose.Models.KeyEntity> key_entities)
    {   
        this.Issuer = issuer;
        this.KeyEntities = key_entities.Select(k =>
                        new SelectListItem()
                        {   
                            Selected = (k.Id == issuer.KeyEntity.Id),
                            Text = k.Id.ToString(),
                            Value = k.Id.ToString()
                        }); 
    }   
}   

Op/Edit.chtml(Razor)

@model AdConnect.Models.OpViewModel
@using (Html.BeginForm()) {

    <div class="editor-field">
        @Html.DropDownListFor(model => model.Issuer.KeyEntity.Id,
                                Model.KeyEntities)
    </div>

}   

操作控制器

    [HttpPost]
    public ActionResult Edit(Models.OpViewModel obj)
    {   
        if (ModelState.IsValid)
        { 
            //  This works for most data fields of Issuer, but KeyEntity's Id 
            //  (dbo.Issuers.KeyEntity_Id) is not updated.
            //
            //  ctx.Entry(obj.Issuer).State = System.Data.EntityState.Modified

            //  So load Issuer and KeyEntity from the database and update.

            var issuer = ctx.Issuers.Find(obj.Issuer.Id);
            if (obj.Issuer.KeyEntity != null)
            {   
                 issuer.KeyEntity =
                    ctx.KeyEntities.Find(obj.Issuer.KeyEntity.Id);
            }   
            ctx.Entry(issuer).CurrentValues.SetValues(obj.Issuer);

            ctx.SaveChanges();
            return RedirectToAction("Index");
        }

        return View(obj);
    }

【问题讨论】:

    标签: asp.net-mvc entity-framework razor


    【解决方案1】:

    我认为您对导航属性的工作方式有所了解。 EF 可以自动填充它们,因此您无需在对象的构造函数中执行此操作。

    阅读我关于导航属性的文章here

    此外,就您的控制器更新代码而言,此类更新的正常路径是:加载、修改、保存。

    var issuer = ctx.Issuers.Include(i=>i.KeyEntity).SingleOrDefault(i=>i.Id == obj.Issuer.Id);
    issuer.Whatever = obj.Issuer.Whatever; //note prehaps you want something like CopyMatchinProperties here
    ctx.SaveChanges();
    

    【讨论】:

    • 非常感谢卢克。你的文章很适合我这样的新手。但我想必须有更好的方法来提供 ViewModel 和更好的模板语法供选择。 KeyEntity 以外的其他字段在一行 ctx.Entry(obj.Issuer).State = System.Data.EntityState.Modified 中更新,但 KeyEntity 不更新。这是一个问题。
    • 嗨 Hideki,我通常将数据模型和视图模型完全分开,这意味着我实际上根本没有从视图中获取数据模型。这是相当普遍的做法,因为它是一种抽象应用程序的两个不同部分的方法。我建议进一步阅读有关此方法及其重要性的信息。 howmvcworks.net/OnModelsAndViewModels/ToModelOrViewModel, stackoverflow.com/questions/5264009/…
    • 但是,如果您确实希望将数据模型一直发送到您的视图,我认为您还需要在模型接触的所有其他实体上设置修改后的状态。 (例如您描述的示例中的 KeyEntity)。
    • 再次感谢卢克。我稍后会尝试,因为这周刚刚结束。 :-)
    • 完全是我的误解。 MVC EF 永远不会像 Django(Python 框架)ModelForm 那样从数据存储中加载现有模型数据。程序员必须编写代码来加载现有模型数据,更新已修改的字段并将其保存回数据存储。无论如何,非常感谢你,卢克。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-01
    • 2019-12-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多