0

I have a Group model/table:

namespace Project
{
    #region Usings

    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;

    #endregion

    [Table("Groups")]
    public class Group
    {

    public Group()
    {
        this.Pk = Guid.NewGuid();
    }

    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    [Key]
    [Required]
    public Guid Pk
    {
        get;
        set;
    }

    public virtual ICollection<Group> Parents
    {
        get;
        set;
    }

    public virtual ICollection<Group> Children
    {
        get;
        set;
    }

    public virtual ICollection<Document> Documents
    {
        get;
        set;
    }

    ...
}

A group can have many groups as either a child or parent, as well as many documents.

I have the relationships wired up in Fluent API as so:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
        modelBuilder.Entity<Group>()
                    .HasMany(e => e.Parents)
                    .WithMany(e => e.Children)
                    .Map(e =>
                         {
                             e.MapLeftKey("ParentPk");
                             e.MapRightKey("ChildPk");
                             e.ToTable("GroupMappings");
                         });

        modelBuilder.Entity<Group>()
                    .HasMany(e => e.Documents)
                    .WithMany(e => e.Groups)
                    .Map(e =>
                         {
                             e.MapLeftKey("DocumentPk");
                             e.MapRightKey("GroupPk");
                             e.ToTable("DocumentMappings");                           
                         });
 }

When I generate the SQL for these models, the relationship between Groups and Documents (DocumentMappings) has ON DELETE CASCASDE:

ALTER TABLE [dbo].[DocumentMappings] ADD CONSTRAINT [FK_dbo.DocumentMappings_dbo.Documents_GroupPk] FOREIGN KEY ([GroupPk]) REFERENCES [dbo].[Documents] ([Pk]) ON DELETE CASCADE

But the GroupMappings does not:

ALTER TABLE [dbo].[GroupMappings] ADD CONSTRAINT [FK_dbo.GroupMappings_dbo.Groups_ParentPk] FOREIGN KEY ([ParentPk]) REFERENCES [dbo].[Groups] ([Pk])
ALTER TABLE [dbo].[GroupMappings] ADD CONSTRAINT [FK_dbo.GroupMappings_dbo.Groups_ChildPk] FOREIGN KEY ([ChildPk]) REFERENCES [dbo].[Groups] ([Pk])

Visual representation of the tables: Table relationships

What could be wrong with my mappings for Group (Parent/Children) that is causing ON DELETE CASCADE to not be "enabled"? Is it related to it being a reference on the same type?

Disclaimer: I have seen a few posts saying this can not be done because you "can't use CASCADE DELETE on self referencing table in SQL SERVER." (Entity Framework 6 Code-First cascade delete on self referencing entity). I am using a mapping table in this case, so this should not be the situation.

Community
  • 1
  • 1
Ryan Mendoza
  • 920
  • 1
  • 13
  • 27

1 Answers1

0

Is it related to it being a reference on the same type?

Yes it is. The GroupMappings table has two foreign keys. If you try to set them bot to cascading delete you will get this exception:

Introducing FOREIGN KEY constraint 'contraintName' on table 'GroupMappings' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.

With two foreign keys, if you delete a Group there would multiple cascade paths to deleting GroupMappings. Sql Server has this restriction that it doesn't allow this, even when the paths end up at the same table.

EF has knowledge of this restriction and doesn't want to choose for you which FK it equips with cascaded delete. It can't do both.

Gert Arnold
  • 105,341
  • 31
  • 202
  • 291
  • Would it be a valid solution to set both FKs to ON CASCADE DELETE after the schema has been created, then? After doing this in test database it _appears_ to be working. – Ryan Mendoza Sep 18 '15 at 23:08
  • Well, I can't make both FKs cascading. Sql Server disallows it. But one would be enough, and yes, it would be a viable solution. – Gert Arnold Sep 19 '15 at 10:31