简体   繁体   English

实体框架核心代码优先-0..1至多关系和级联删除

[英]Entity Framework Core code first - 0..1 to many relationship and cascade delete

I'm trying to create a commenting system backed by Entity Framework Core where multiple entities of different type can have comments attached to them. 我正在尝试创建一个由Entity Framework Core支持的评论系统,其中不同类型的多个实体可以附加评论。

These are my entities. 这些是我的实体。 (In the real application there are about 7 in total with varying relationships but this is how it generally looks) (在实际的应用程序中,总共有大约7个具有不同的关系,但这通常是它的外观)

public class Comment : IEntityBase
{
    public int Id { get; set; }

    public int? FreezerId{ get; set; }
    public Freezer Freezer { get; set; }
    public int? BoxId{ get; set; }
    public Box Box{ get; set; }
    public string Author { get; set; }
    public DateTime CreatedAt { get; set; }
    public string Content { get; set; }
}

public class Freezer: IEntityBase
{
    public int Id { get; set; }

    public string Name { get; set; }
    public string Location { get; set; }
    public ICollection<Box> Boxes{ get; set; }
    public ICollection<Comment> Comments { get; set; }
}

public class Box: IEntityBase
{
    public int Id { get; set; }

    public Freezer Freezer{get; set;}
    public int FreezerId{get; set;}
    public string Data{ get; set; }
    public ICollection<Comment> Comments { get; set; }
}

I want the Comment entity to be attached to one Freezer or one Box, but not both at the same time. 我希望将Comment实体附加到一个冰柜或一个Box,但不能同时附加到两者。

I defined the relationship in the fluent API as the following: 我在流畅的API中定义了以下关系:

 builder.Entity<Box>(boxBuilder=>
        {
            boxBuilder.HasOne(box=> box.Freezer)
                .WithMany(freezer => freezer.boxes)
                .HasForeignKey(box => box.FreezerId)
                .IsRequired()
                .OnDelete(DeleteBehavior.Cascade);

            boxBuilder.HasMany(box => box.Comments)
                .WithOne(comment => comment.Box)
                .HasForeignKey(comment => comment.BoxId)
                .OnDelete(DeleteBehavior.Cascade);
        });

 builder.Entity<Freezer>(freezerBuilder =>
        {
            freezerBuilder.HasMany(freezer=> freezer.Comments)
                .WithOne(comment => comment.Freezer)
                .HasForeignKey(comment => comment.FreezerId)
                .OnDelete(DeleteBehavior.Cascade);
        });

When I try to update the database to this model I get the following error: 当我尝试将数据库更新为该模型时,出现以下错误:

System.Data.SqlClient.SqlException: Introducing FOREIGN KEY constraint 'FK_Comment_Boxes_BoxId' on table 'Comment' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.

I think the error comes from the Box and the Freezer property in the Comment class not being optional which would make this a 1 to many relationship instead of a 0..1 to many relationship which is what I want. 我认为错误来自Comment类中的Box和Freezer属性不是可选的,这将使它成为1对多的关系,而不是我想要的0..1对多的关系。

With Entity Framework 6 I would just use the .HasOptional() method, but this doesn't exist in Entity Framework Core 对于Entity Framework 6,我将只使用.HasOptional()方法,但这在Entity Framework Core中不存在

I think one way to solve this would be to just subclass the Comment class and create a unique comment class for each entity that can be commented on and move the foreign key and reference property to that subclass instead. 我认为解决此问题的一种方法是仅对Comment类进行子类化,并为每个可以对其进行注释的实体创建一个唯一的注释类,然后将外键和引用属性移至该子类。

But it feels like I shouldn't have to do it this way. 但这似乎让我不必这样做。

You have to disable the cascade delete( DeleteBehavior.Restrict ) then it will works for you: 您必须禁用级联删除( DeleteBehavior.Restrict ),然后它将为您工作:

 modelBuilder.Entity<Box>(boxBuilder =>
        {
          boxBuilder.HasOne(box => box.Freezer)
              .WithMany(freezer => freezer.Boxes)
              .HasForeignKey(box => box.FreezerId)
              .IsRequired()
              .OnDelete(DeleteBehavior.Cascade);

          boxBuilder.HasMany(box => box.Comments)
              .WithOne(comment => comment.Box)
              .HasForeignKey(comment => comment.BoxId)
              .OnDelete(DeleteBehavior.Restrict);
        });

        modelBuilder.Entity<Freezer>(freezerBuilder =>
        {
          freezerBuilder.HasMany(freezer => freezer.Comments)
              .WithOne(comment => comment.Freezer)
              .HasForeignKey(comment => comment.FreezerId)
              .OnDelete(DeleteBehavior.Restrict);
        });
        base.OnModelCreating(modelBuilder);
      }

Usage: 用法:

using (var myConext = new MyDbContext())
      {
        myConext.Database.EnsureCreated();
        myConext.Boxes.Add(new Box() {Freezer =  new Freezer()});
        myConext.SaveChanges();
      }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM