为什么实体框架不在这里更新子对象?
本文关键字:对象 更新 在这里 实体 框架 为什么 | 更新日期: 2023-09-27 18:17:29
我有一个具有MailingAddress
属性的Customer
模型-这是指向Address
类的导航属性:
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public virtual Address MailingAddress { get; set; }
}
我有一个表单,它发布了一个包含customer
的视图模型,以及邮寄地址。下面是控制器中的save方法:
public ActionResult Save(CustomerFormViewModel viewModel)
{
if (!ModelState.IsValid)
{
return View("CustomerForm", viewModel);
}
if (viewModel.Customer.Id == 0)
{
_context.Customers.Add(viewModel.Customer);
}
else
{
var customerInDb = _context.Customers
.Single(c => c.Id == viewModel.Customer.Id);
_context.Entry(customerInDb).CurrentValues.SetValues(viewModel.Customer);
}
_context.SaveChanges();
return RedirectToAction("Index", "Customers");
}
当发布一个新客户时,一切工作正常(大多数情况下,请参见下面的注释),并且该客户与相应的地址记录一起创建。但是,当我编辑一个现有条目时,客户更新了,但地址没有更新。我验证了更新后的地址正在customer对象中传递。如果我添加这样一行:
_context.Entry(customerInDb.MailingAddress).CurrentValues.SetValues(viewModel.Customer.MailingAddress);
然后更新。
这里的孩子仍然被认为是一个独立的实体吗?我认为,因为它是Customer
的属性,我正在抓取它会自动保存与父。为什么这对新记录有效,而对更新记录无效?
关于新记录创建的一个注意事项-创建了一个Customer
记录,并有一个MailingAddress_Id
指向地址。Address
记录也被创建,但它的Customer_Id
是空的…为什么EF没有在关系的那一边添加键?地址模型和视图模型代码,如果它有帮助:
public class Address
{
public int Id { get; set; }
public string Street1 { get; set; }
// Snip a bunch of address data properties
public virtual Customer Customer { get; set; }
}
public class CustomerFormViewModel
{
// Snip irrelevant properties
public Customer Customer { get; set; }
}
首先,如果您的Customer
和Address
是一对一关系,那么不需要外键。实际上,在一对一关系中,关系依赖端的主键也是主端的外键。其次,当你创建新的Customer
时,你使用context.Customers.Add(viewModel.Customer);
,它添加了所有子模型的模型,但是当你尝试使用_context.Entry(customerInDb).CurrentValues.SetValues(viewModel.Customer);
更新时,它不添加所有子导航属性,要这样做,你必须明确地告诉它到EntityFramework:
var customerInDb = _context.Customers
.Single(c => c.Id == viewModel.Customer.Id);
_context.Entry(customerInDb)
.CurrentValues
.SetValues(viewModel.Customer);
var mailingAddressInDb = _context.Addresses
.Single(m => m.Id = viewModel.Customer.MailingAddress.Id);
_context.Entry(mailingAddressInDb)
.CurrentValues
.SetValues(viewModel.Customer.MailingAddress);
应该对你有用。但这有点尴尬。当你有几十个模型时,你甚至不想想象它。
的好消息好消息是,有一个API可以从根本上解决这个问题。你的问题只需要几个步骤就能解决。您使用Install-Package Ma.EntityFramework.GraphManager
从NuGet安装它,配置您的模型以满足先决条件(这很容易),并使用一行代码处理整个图形:
public ActionResult Save(CustomerFormViewModel viewModel)
{
if (!ModelState.IsValid)
{
return View("CustomerForm", viewModel);
}
// Define state of whole graph with single line
_context.AddOrUpdate(viewModel.Customer);
_context.SaveChanges();
return RedirectToAction("Index", "Customers");
}
请查看CodeProject的文章以获得快速演示。它有示例代码,因此您可以下载并检查它。我是这个API的所有者,我准备回答你的问题。