外键约束,带有子对象集合的 EF
Posted
技术标签:
【中文标题】外键约束,带有子对象集合的 EF【英文标题】:Foreign key constraint, EF with collection of childobjects 【发布时间】:2012-04-27 13:05:23 【问题描述】:我正在尝试更新模型,但收到错误“操作失败:无法更改关系,因为一个或多个外键属性不可为空。当对关系进行更改时,相关外键属性设置为空值。如果外键不支持空值,则必须定义新的关系,必须为外键属性分配另一个非空值,或者不相关的对象必须删除。”
根据我从The relationship could not be changed because one or more of the foreign-key properties is non-nullable 了解到的情况,问题可能在于 Entity Framework 如何处理我的虚拟 ICollection
但是,当使用脚手架存储库模式时,我不确定如何实现该解决方案。我是否必须编辑 Save() 方法 ParentObjectRepository 类?
其实我真的觉得一定有办法让EF明白这一点。我看不出 EF 团队是如何思考“可能没有人使用具有外键约束的对象集合,我们不支持”。
更新 添加代码
[HttpPost]
public ActionResult Edit(int id, FormCollection formCollection)
var eventRepository = new MagnetEventRepository();
var original = eventRepository.Find(id);
UpdateModel(original);
eventRepository.Save();
return RedirectToAction("Details", "Home", new slug = original.Slug );
public void Save()
context.SaveChanges();
更多代码:
public class MagnetEvent
public virtual int Id get; set;
[Required]
public virtual string Name get; set;
[Required]
[DisplayFormat(DataFormatString = "0:yyyy-MM-dd HH:mm")]
[DataType(DataType.DateTime)]
public virtual DateTime? StartDate get; set;
public virtual string Description get; set;
[StringLength(100)]
public virtual string Slug get; set;
public virtual int MaximumCapacity get; set;
[DataType(DataType.Currency)]
public virtual int TicketPrice get; set;
public virtual int LocationId get; set;
public virtual Location Location get; set;
public virtual Collection<Ticket> Tickets get; set;
public virtual Collection<AttendeeInformationField> CaptureAttendeeInformationFields get; set;
public virtual int CustomerId get; set;
[Required]
public virtual CUSTOMER Customer get; set;
Save()-方法来自 MagnetEventRepository,它是从上面的类中搭建的。
另一个更新 我通过将 AttendeeInformationField 中的 MagnetEventId 更改为可为空的 int 成功消除了错误。检查数据库时,我可以确切地看到问题所在。
假设我有一个值为“E-mail”的 AttendeeInformationField。当我编辑我的 MagnetEvent 时,AttendeeInformationField 将 MagnetEventId 更新为 null,然后添加具有正确 MagnetEventId 和值的新帖子。
我非常希望更新 AttendeeInformationField 中的帖子。
【问题讨论】:
你能发布你的查询和更新代码吗? 当然,我更新了原帖。 【参考方案1】:您能否为您的事件对象添加代码。你称之为原创的那个。
这可能是因为 UpdateModel 更改了相关对象的一些信息,如果这样就不好了。虽然我看不到所有代码,但不确定这一点。
我更喜欢不使用 UptadeModel,而是使用 inputmodel 或您的 MVC 模型作为参数,并手动将 chages 映射到加载的原始对象。
另一个问题是我看不到 eventRepository.Save();
真的会做 SaveShages 吗?可以?我可以用另一种方法保存一些上下文代码吗?
【讨论】:
【参考方案2】:正如例外所说,它看起来像您的关联集合或其他关联对象无法找到有效的 ID 值。
您是否急切加载关联的对象?喜欢客户?
【讨论】:
据我了解,虚拟意味着急切加载,所以是的!从我链接到的那篇文章中,我认为它与我的 ICollection 调试时,一切似乎都很好,但保存失败 虚拟的意思是开启后可以延迟加载。 Eagerload 是当您说它应包括关联时。如果您调试 Find(...) 是否给您一个 id 和关联中没有空值的 cls? 对不起,我的错。我有延迟加载。当我调试时,我可以看到所有的值。【参考方案3】:需要注意的一点是,您不应该在 Customer 上使用 [Required],因为它是从您的 FK 不可为空这一事实推断出来的。仅当模型中没有 FK 时,才应在导航属性上使用 required。
要尝试诊断问题,您能否加载对象并在调试器中查看它,您应该期望 locationId 和 CustomerId 都具有非零值。
【讨论】:
是的,LocationId 和 CustomerId 在调试时都有正确的值。在我尝试实现 ICollection 之前,一切都运行良好 我在原帖中添加了更多信息【参考方案4】:我找到了解决问题的方法。当涉及到 UpdateModel 和包含 ICollection 的模型时,这似乎是 ASP.NET MVC 中的一个错误(?)。
解决方案是覆盖默认行为,如本博文所述:http://www.codetuning.net/blog/post/Binding-Model-Graphs-with-ASPNETMVC.aspx
更新 我找到了解决办法!以上仅在更新集合中的现有项目时有效。为了解决这个问题,我必须手动检查并添加新的 AttendeeInformationFields。像这样:
[HttpPost]
public ActionResult Edit(int id, MagnetEvent magnetEvent)
var eventRepository = new MagnetEventRepository();
var original = eventRepository.Find(id);
UpdateModel(original);
foreach (var attendeeInformationField in magnetEvent.CaptureAttendeeInformationFields)
var attendeeInformationFieldId = attendeeInformationField.Id;
if (original.CaptureAttendeeInformationFields.AsQueryable().Where(ai => ai.Id == attendeeInformationFieldId).Count() == 0)
original.CaptureAttendeeInformationFields.Add(attendeeInformationField);
eventRepository.Save();
与修改后的 DefaultModelBinder 一起,这实际上适用于编辑和添加。目前我还没有尝试删除。
不过,我希望有一种更简单的方法可以做到这一点。似乎需要大量编码才能完成一项非常基本的任务。
【讨论】:
以上是关于外键约束,带有子对象集合的 EF的主要内容,如果未能解决你的问题,请参考以下文章
外键 Laravel 8 foreignId + 约束 - 无法添加或更新子行:外键约束失败