【问题标题】:Foreign key constraint, EF with collection of childobjects外键约束,带有子对象集合的 EF
【发布时间】: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 中的帖子。

【问题讨论】:

  • 你能发布你的查询和更新代码吗?
  • 当然,我更新了原帖。

标签: asp.net-mvc entity-framework repository-pattern entity-framework-migrations


【解决方案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 一起,这实际上适用于编辑和添加。目前我还没有尝试删除。

    不过,我希望有一种更简单的方法可以做到这一点。似乎需要大量编码才能完成一项非常基本的任务。

    【讨论】:

      猜你喜欢
      • 2021-04-07
      • 1970-01-01
      • 2021-09-30
      • 2020-10-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多