在一对多关系中从父集合中删除子实体时删除子实体 Entity Framework
Delete child entity when removed from parent collection in one to many relationship Entity Framework
我有以下数据库设置:
表格映射如下:
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);
}
}
当我尝试从 OrderItem 的集合中删除 OrderItemSet 时 Entity Framework 试图将 OrderItemSet 中的外键设置为 null 而不是删除行,即使外键不可为 null,因此抛出异常说明外键不能设置为空。
this.OrderItemSets.Remove(orderItemSet);
我不知道我的映射有什么问题 Entity Framework 认为它应该将外键设置为 null 而不是删除行。
您需要的是 OderItem
和 OrderItemSet
之间的 identifying relationship。来自上面提供的 link 中的 识别和非识别关系的注意事项 部分:
Removing the relationship deletes the dependent object. Calling the Remove method on the EntityCollection marks both the relationship and the dependent object for deletion.
您应该考虑 Order
和 OrderItem
的相同类型的关系。
基本思想是,对于 OrderItemSet
的模型,您将 OrderItem
的外键作为 OrderItemSet
的主键的一部分,从而创建 复合键。在 OrderItemSet
的映射中,尝试像这样映射主键:
public OrderItemSetMapping()
{
...
this.HasKey(ois => new { ois.OrderItemSetId, ois.OrderItemId });
...
}
万一doesn't work with the fluent API,则尝试创建具有属性的映射:
public class OrderItemSet
{
[Key, ForeignKey("OrderItem"), Column(Order = 1)]
public <YourKeyType> OrderItemId { get; set; }
[Key, Column(Order = 2)]
public <YourKeyType> OrderItemSetId { get; set; }
...
}
为什么不直接删除 child:
context.OrderItemSets.Remove(orderItemSet);
context.SaveChanges();
当您从 parent 中删除 child 时,您可能想将其添加到另一个 parent,因此 Entity Framework 删除child 自动。你应该自己做。
我已经按照Abbondanza的建议解决了这个问题。首先创建包含外键的实体键(这将强制 entity framework 删除子项,因为没有外键它就不能存在):
public OrderItemSetMapping()
{
...
this.HasKey(ois => new { ois.OrderItemSetId, ois.OrderItemId });
...
}
Entity Framework 现在将删除实体,如果从父集合中删除,但是由于 OrderItemSetId 是一个标识列,这会产生另一个问题,Entity Framework 现在想在该列中插入一个值将新项目添加到父集合时(这将抛出异常)。通过在此列上指定 DatabaseGenerationOption,问题将得到解决:
public OrderItemSetMapping()
{
...
this.Property(r => r.OrderItemSetId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
...
}
我有以下数据库设置:
表格映射如下:
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);
}
}
当我尝试从 OrderItem 的集合中删除 OrderItemSet 时 Entity Framework 试图将 OrderItemSet 中的外键设置为 null 而不是删除行,即使外键不可为 null,因此抛出异常说明外键不能设置为空。
this.OrderItemSets.Remove(orderItemSet);
我不知道我的映射有什么问题 Entity Framework 认为它应该将外键设置为 null 而不是删除行。
您需要的是 OderItem
和 OrderItemSet
之间的 identifying relationship。来自上面提供的 link 中的 识别和非识别关系的注意事项 部分:
Removing the relationship deletes the dependent object. Calling the Remove method on the EntityCollection marks both the relationship and the dependent object for deletion.
您应该考虑 Order
和 OrderItem
的相同类型的关系。
基本思想是,对于 OrderItemSet
的模型,您将 OrderItem
的外键作为 OrderItemSet
的主键的一部分,从而创建 复合键。在 OrderItemSet
的映射中,尝试像这样映射主键:
public OrderItemSetMapping()
{
...
this.HasKey(ois => new { ois.OrderItemSetId, ois.OrderItemId });
...
}
万一doesn't work with the fluent API,则尝试创建具有属性的映射:
public class OrderItemSet
{
[Key, ForeignKey("OrderItem"), Column(Order = 1)]
public <YourKeyType> OrderItemId { get; set; }
[Key, Column(Order = 2)]
public <YourKeyType> OrderItemSetId { get; set; }
...
}
为什么不直接删除 child:
context.OrderItemSets.Remove(orderItemSet);
context.SaveChanges();
当您从 parent 中删除 child 时,您可能想将其添加到另一个 parent,因此 Entity Framework 删除child 自动。你应该自己做。
我已经按照Abbondanza的建议解决了这个问题。首先创建包含外键的实体键(这将强制 entity framework 删除子项,因为没有外键它就不能存在):
public OrderItemSetMapping()
{
...
this.HasKey(ois => new { ois.OrderItemSetId, ois.OrderItemId });
...
}
Entity Framework 现在将删除实体,如果从父集合中删除,但是由于 OrderItemSetId 是一个标识列,这会产生另一个问题,Entity Framework 现在想在该列中插入一个值将新项目添加到父集合时(这将抛出异常)。通过在此列上指定 DatabaseGenerationOption,问题将得到解决:
public OrderItemSetMapping()
{
...
this.Property(r => r.OrderItemSetId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
...
}