外键约束,带有子对象集合的 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的主要内容,如果未能解决你的问题,请参考以下文章

SQLite EF Core - '外键约束失败'

实体框架:0..1 对多外键约束无法识别?

Sequelize - 无法添加或更新子行:外键约束失败

外键 Laravel 8 foreignId + 约束 - 无法添加或更新子行:外键约束失败

EF Core SQLite 错误 19:尽管配置了一对多,但“外键约束失败”

判断子表外键约束参数类型