外键约束,EF与子对象的集合

时间:2012-04-16 07:22:22

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

我试图更新模型,但得到错误"操作失败:由于一个或多个外键属性不可为空,因此无法更改关系。当对关系进行更改时,相关的外键属性将设置为空值。如果外键不支持空值,则必须定义新关系,必须为外键属性分配另一个非空值,或者必须删除不相关的对象。"

根据我对The relationship could not be changed because one or more of the foreign-key properties is non-nullable的理解,问题可能在于实体框架如何处理我的虚拟ICollection

但是,在使用scaffolded存储库模式时,我并不确定如何实现该解决方案。我是否必须编辑Save() - 方法ParentObjectRepository-class?

实际上我真的认为必须有某种方法让EF理解这一点。我无法看到EF团队的想法和#34;可能没有人使用具有外键约束的对象集合,不能支持"。

更新 添加了代码

[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更改为nullable int来成功删除了错误。在检查数据库时,我可以确切地看到错误。

假设我有一个单独的AttendeeInformationField,其值为&#34;电子邮件&#34;。当我编辑我的MagnetEvent时,AttendeeInformationField将MagnetEventId更新为null,然后使用正确的MagnetEventId和Value添加一个新帖子。

我非常喜欢AttendeeInformationField中的帖子而不是更新。

4 个答案:

答案 0 :(得分:0)

可以为事件对象添加代码吗?你称之为原创的那个。

可能是因为UpdateModel更改了关联对象的一些信息,如果是这样,那就不好了。不确定这一点虽然我看不到所有的代码。

我更喜欢不使用UptadeModel,而是使用inputmodel或MVC模型作为参数,并手动将chages映射到加载的原始对象。

Antoher问题是我看不清楚  eventRepository.Save();

真的做了SaveShages吗?可以?我可以在另一种方法Save?

中查看一些上下文代码

答案 1 :(得分:0)

正如例外情况所说,它会像您的关联集合或其他相关对象一样找不到有效的ID值。

您是否急于加载相关对象?喜欢顾客?

答案 2 :(得分:0)

有一点值得注意的是,由于您的FK不可为空,因此您不应该将客户的[必需]作为推断。如果模型中没有FK,则必须仅在导航属性上使用。

要尝试诊断问题,可以加载对象并在调试器中查看它,您应该期望locationId和CustomerId都具有非零值。

答案 3 :(得分:0)

我找到了解决问题的方法。当涉及到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一起,这实际上适用于编辑和添加。现在我还没有尝试删除。

不过,我希望有一种更简单的方法可以做到这一点。看起来像很多编码来完成一项非常基本的任务。