首页 > 解决方案 > ASP .NET MVC - 更新一对一数据失败

问题描述

我正在使用 ASP .NET MVC5 和 EF6 构建一个 Web 应用程序。我有一个一对一的关系,定义如下:

public class Client 
{
  public int ClientId { get; set; }  
  [Required]
  public string Name { get; set; }

  public Address Address { get; set; }
}

public class Address 
{
  [ForeignKey("Client")]
  public int AddressId { get; set; }  
  [Required]
  public string StreetName { get; set; }

  public Client Client { get; set; }
}

地址是从属端。启用迁移并更新数据库后,将创建两个表,其中Address 表包含一个 ClientId 列,作为外键的结果。

然后我开始为这些类生成控制器和视图。

对于地址,我正在尝试修改创建/编辑方法和视图,以便能够添加新地址并将其关联到现有客户端,这正是本教程中所做的:

https://docs.microsoft.com/en-us/aspnet/mvc/overview/getting-started/getting-started-with-ef-using-mvc/updating-related-data-with-the-entity-framework-在-an-asp-net-mvc-应用程序中

我的 AddressController 完全按照教程的建议以及各自的视图进行了定制。但是在运行 Web 应用程序时访问“创建”页面时,我可以编写街道名称并从下拉列表中选择客户端的名称(这是我想要的,显示客户端名称而不是 Id)。

点击创建按钮时,出现以下错误:

INSERT 语句与 FOREIGN KEY 约束“FK_dbo.Addresses_dbo.Clients_AddressId”冲突。冲突发生在数据库“myDb”、表“dbo.Clients”、列“ClientId”中。该语句已终止。

这使我相信外键 ClientId 没有像它应该通过在下拉列表中选择一个名称来更新。我尝试添加没有关联地址的新客户端,但即使选择没有关联地址的客户端,错误仍然存​​在。

我也知道,理想情况下,下拉列表实际上应该只显示没有任何关联地址的客户,但我不知道如何实现这一点。

因为我遵循了上述教程的每一步,所以我真的不知道我做错了什么。

任何帮助将不胜感激!如果需要发布更多代码,我会这样做,只是为了缩短这篇已经很长的帖子而没有这样做。

更新代码

地址控制器.cs

public class AddressesController : Controller
    {
        private ApplicationDbContext db = new ApplicationDbContext();

        // GET: Addresses
        public ActionResult Index()
        {
            var addresses = db.Addresses.Include(m => m.Client);
            return View(addresses.ToList());
        }

        // GET: Addresses/Details/5
        public ActionResult Details(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            Address address = db.Addresses.Find(id);
            if (address == null)
            {
                return HttpNotFound();
            }
            return View(address);
        }

    // GET: Address/Create
        public ActionResult Create()
        {
            PopulateClientsDropDownList(); 
            return View();
        }

        // POST: Addresses/Create
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create([Bind(Include = "AddressId,StreetName,ClientId")] Address address)
        {
            try
            {
                if (ModelState.IsValid)
                {

                    db.Addresses.Add(addresses);
                    db.SaveChanges();
                    return RedirectToAction("Index");
                }
            }
            catch (DataException dex)
            {

                ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
                ErrorSignal.FromCurrentContext().Raise(dex);
            }
            PopulateClientsDropDownList(address.ClientId);
        return View(address);
        }

    // GET: Addresses/Edit/5
        public ActionResult Edit(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }

        Address address = db.Address.Find(id);
            if (address == null)
            {
                return HttpNotFound();
            }
            PopulateClientsDropDownList(address.ClientId); 

            return View(address);
        }

        // POST: Addresses/Edit/5
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost, ActionName("Edit")]
        [ValidateAntiForgeryToken]
        public ActionResult EditPost(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            var addressToUpdate = db.Addresses.Find(id);
            if (TryUpdateModel(addressToUpdate, "",
                new string[] { "StreetName", "ClientId" }))
            {
                try
                {
                    db.SaveChanges();
                    return RedirectToAction("Index");
                }
                catch (RetryLimitExceededException dex)
                {
                    ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
                    ErrorSignal.FromCurrentContext().Raise(dex);
                }
            }
            PopulateAddressesDropDownList(addressToUpdate.ClientId);
            return View(addressToUpdate);
        }

    private void PopulateClientsDropDownList(object selectedClient = null)
        {
            var clientsQuery = from d in db.Clients
                               orderby d.Name
                               select d;
            ViewBag.ClientId = new SelectList(clientsQuery, "ClientId", "Name", selectedClient);
        }
}

Create.cshtml (缩短)

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        <h4>Addresses</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        @*<div class="form-group">
                @Html.LabelFor(model => model.AddressId, "AddressId", htmlAttributes: new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.DropDownList("AddressId", null, htmlAttributes: new { @class = "form-control" })
                    @Html.ValidationMessageFor(model => model.AddressId, "", new { @class = "text-danger" })
                </div>
            </div>*@

        <div class="form-group">
            @Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            <label class="control-label col-md-2" for="ClientId">Client Name</label>
            <div class="col-md-10"> 
                @Html.DropDownList("ClientId", null, htmlAttributes: new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.ClientId, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}

标签: c#asp.netasp.net-mvcentity-frameworkentity-framework-6

解决方案


推荐阅读