Entity framework 从一对多关系实体框架中的父集合中删除子实体

Entity framework 从一对多关系实体框架中的父集合中删除子实体,entity-framework,one-to-many,foreign-key-relationship,Entity Framework,One To Many,Foreign Key Relationship,我有以下数据库设置: 这些表映射如下: public class OrderMapping : EntityTypeConfiguration<Order> { public OrderMapping() { this.ToTable("Orders", "prf"); this.HasKey(o => o.OrderId); this.HasMany(o => o.OrderItems)

我有以下数据库设置:

这些表映射如下:

public class OrderMapping : EntityTypeConfiguration<Order>
{
    public OrderMapping()
    {
        this.ToTable("Orders", "prf");

        this.HasKey(o => o.OrderId);

        this.HasMany(o => o.OrderItems)
            .WithRequired(oi => oi.Order)
            .HasForeignKey(oi => oi.OrderId);

        this.HasRequired(o => o.Institution)
            .WithMany()
            .HasForeignKey(o => o.InstitutionId);

        this.Property(o => o.IsConfirmed)
            .IsRequired();

        this.Ignore(o => o.Id);
    }
}

public class OrderItemMapping : EntityTypeConfiguration<OrderItem>
{
    public OrderItemMapping()
    {
        this.ToTable("OrderItems", "prf");

        this.HasKey(oi => oi.OrderItemId);

        this.HasRequired(oi => oi.Order)
            .WithMany(oi => oi.OrderItems)
            .HasForeignKey(oi => oi.OrderId);

        this.HasRequired(oi => oi.Proficiency)
            .WithMany()
            .HasForeignKey(oi => oi.ProficiencyId);

        this.HasOptional(oi => oi.Enrolment)
            .WithMany()
            .HasForeignKey(oi => oi.EnrolmentId);

        this.HasMany(oi => oi.OrderItemSets)
            .WithRequired(ois => ois.OrderItem)
            .HasForeignKey(ois => ois.OrderItemId);

        this.Property(oi => oi.DateCreated);

        this.Ignore(oi => oi.Id);
    }
}

public class OrderItemSetMapping : EntityTypeConfiguration<OrderItemSet>
{
    public OrderItemSetMapping()
    {
        this.ToTable("OrderItemSets", "prf");

        this.HasKey(ois => ois.OrderItemSetId);

        this.HasRequired(ois => ois.OrderItem)
            .WithMany(ois => ois.OrderItemSets)
            .HasForeignKey(ois => ois.OrderItemId);

        this.Property(ois => ois.NumberOfSets);
        this.Property(ois => ois.Month);
    }
}
我不知道我的映射有什么问题,让Entity Framework认为应该将foreignkey设置为null而不是删除行。

您需要的是介于
OderItem
OrderItemSet
之间的映射。从上文提供的链接中识别和不识别关系的注意事项部分:

删除关系将删除从属对象。在EntityCollection上调用Remove方法会标记要删除的关系和从属对象

你应该考虑同一类型的关系:<代码>订单< /代码>和<代码> OrthItgs< /C> > < /P> 基本思想是,对于

OrderItemSet
模型,将
OrderItem
的外键作为
OrderItemSet
主键的一部分,从而创建一个复合键。在
OrderItemSet
的映射中,尝试这样映射主键:

public OrderItemSetMapping()
{
    ...

    this.HasKey(ois => new { ois.OrderItemSetId, ois.OrderItemId });

    ...
}
在这种情况下,请尝试使用属性创建映射:

public class OrderItemSet
{
    [Key, ForeignKey("OrderItem"), Column(Order = 1)]
    public <YourKeyType> OrderItemId { get; set; }

    [Key, Column(Order = 2)]
    public <YourKeyType> OrderItemSetId { get; set; }

    ...
}
公共类OrderItemSet
{
[键,外键(“订单项”),列(订单=1)]
公共OrderItemId{get;set;}
[键,列(顺序=2)]
public OrderItemSetId{get;set;}
...
}

为什么不直接删除子项:

context.OrderItemSets.Remove(orderItemSet);
context.SaveChanges();

从父级中删除子级时,可能希望将其添加到另一个父级,因此Entity Framework不适合自动删除该子级。你应该自己做。

我已经按照阿本丹扎的建议解决了这个问题。首先,创建实体的键以包含外键(这将强制实体框架删除子项,因为没有外键它无法存在):

如果从父集合中删除实体,Entity Framework现在将删除该实体,但是由于OrderItemSetId是一个标识列,这会产生另一个问题,在向父集合添加新项时,Entity Framework现在希望在该列中插入值(这将引发异常)。通过在此列上指定DatabaseGenerationOption,问题将得到解决:

public OrderItemSetMapping()
{
    ...

    this.Property(r => r.OrderItemSetId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

    ...
}

您看过外键上的
WillCascadeOnDelete
选项了吗?如果父实体被删除,WillCascadeOnDelete将只删除子实体。我正在从父项中删除子项,因此EF正在删除两者之间的关系。但是,由于foreignkey不可为null,因此它也应该删除子项,而不是将foreignkey设置为null。我已删除了如上所述的双重关系,但仍然得到foreignkey不能设置为null的错误。this.HasMany(o=>o.OrderItems).WithRequired(o=>o.Order).HasForeignKey(o=>o.OrderId);而this.HasMany(oi=>oi.OrderItemSets).WithRequired(oi=>oi.OrderItem).HasForeignKey(oi=>oi.OrderItemId);为什么不把我的答案标记为已接受?您基本上使用了我的答案,并添加了一些与问题中所述问题不直接相关的内容。不太好,你知道。@Abbondanza我很抱歉你有这种感觉。我在回答中确实给了你信任,但是第二部分对于问题的完整解决是绝对必要的。
public OrderItemSetMapping()
{
    ...

    this.HasKey(ois => new { ois.OrderItemSetId, ois.OrderItemId });

    ...
}
public OrderItemSetMapping()
{
    ...

    this.Property(r => r.OrderItemSetId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

    ...
}