简体   繁体   中英

Entity Framework many-to-many relationship error

I have two classes:

public class Cluster
{
    public int Id { get; set; }
    public virtual ICollection<Blob> Blobs { get; set; }
}

public class Blob
{
    public int Id { get; set; }
    public virtual ICollection<Cluster> Clusters { get; set; }
}

public ClusterConfiguration ()
{
    this.HasKey(p => p.Id)
        .HasRequired(p => p.Frame)
        .WithMany(p => p.Clusters)
        .HasForeignKey(p => p.FrameId)
        .WillCascadeOnDelete(true)
        ;

    this.HasMany(p => p.Blobs)
        .WithMany(p => p.Clusters)
        ;
}

public BlobConfiguration ()
{
    this.HasKey(p => p.Id)
        .HasRequired(p => p.Frame)
        .WithMany(p => p.Blobs)
        .HasForeignKey(p => p.FrameId)
        .WillCascadeOnDelete(true)
        ;

    this.HasMany(p => p.Clusters)
        .WithMany(p => p.Blobs)
        ;
}

There are references to other tables in these classes but I do not think that is the problem. The error is:

[{"Introducing FOREIGN KEY constraint 'FK_dbo.ClusterBlobs_dbo.Blob_Blob_Id' on table 'ClusterBlobs' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.\\r\\nCould not create constraint. See previous errors."}].

I'm not quite sure how to tell EF to cascade delete Blobs if Clusters are deleted but not to delete Clusters if Blobs are deleted. Please advise.

UPDATE: Using EF5 by the way.

The multiple cascading delete path is actually in effect if you delete a Frame , not a Cluster or Blob :

  • Frame is deleted -> Cascades to Clusters -> Cascades to link table
  • Frame is deleted -> Cascades to Blobs -> Cascades to link table

So, these are the two paths from Frame to the link table.

I would suggest to disable cascading delete for one of the two (or both) relationships from Frame to Cluster or Blob . (Use WillCascadeOnDelete(false) there.) Disabling cascading delete for the link table is not possible on an individual relationship basis. The only way is to disable the convention globally:

modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();

But this will affect all many-to-many relationships in your model.

I'm not quite sure how to tell EF to cascade delete Blobs if Clusters are deleted but not to delete Clusters if Blobs are deleted.

This is by the way not possible. There is no cascading delete between Cluster and Blob because from database viewpoint the many-to-many relationship is actually modeled with two one-to-many relationships with the link table in between. Cascading delete only acts on the link table which is the dependent in the relationships. Cluster and Blob are both principals.

I believe that turning off ManyToManyCascadeDeleteConvention globally is not a wise option. Instead, it's better to turn it off only for the concerned table.

This can be achieved through editing the generated migration file, for property cascadeDelete . For example:

AddForeignKey("dbo.ClusterBlobs", "Blob_Id", "dbo.Blob", "Blob_Id", cascadeDelete: false);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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