Search code examples
c#entity-framework-coreone-to-manyself-referencing-tableef-core-6.0

Self-referencing zero or one to many (0-1 -> N) relation in Entity Framework Core 6


I have this simple entity which may have some children of its own type:

public class File {

    public long Id { get; set; }

    public File? Parent { get; set; }
    public long? ParentId { get; set; }

    public IList<File>? Children { get; set; }

    public string Name { get; set; }
}

Actually, an individual entity may has a parent of its own type or not; and it may be parent for some other entities of its own type (0-1 -> N relationship). I've tried to configure it in Entity Framework Core 6 with these lines of code:

// Didn't work:
builder.HasOne(t => t.Parent).WithMany(t => t.Children)
    .HasForeignKey(t => t.ParentId)
    .OnDelete(DeleteBehavior.Restrict);

Actually I've tried all combinations of HasForeignKey, HasPrincipalKey, DeleteBehavior.Restrict, DeleteBehavior.SetNull, and DeleteBehavior.NoAction with that, but all I got was this:

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

Can anyone help me please?

NOTE: I haven't any other relations on this entity. Actually this is the only entity I ever have in this domain.

UPDATE: It's pretty weird! Looking at the generated SQL seems too odd:

CREATE TABLE [File] (
    [Id] bigint NOT NULL IDENTITY,
    [ParentId] bigint NULL,
    [Name] varchar(32) NOT NULL,
    CONSTRAINT [PK_File] PRIMARY KEY ([Id]),
    CONSTRAINT [FK_File_File_ParentId] FOREIGN KEY ([ParentId])
        REFERENCES [File] ([Id]) ON DELETE CASCADE
);

It seems EF is ignoring the .OnDelete(DeleteBehavior...) command, and it's creating ON DELETE CASCADE part in all cases!


Solution

  • The problem is that you have a cyclic relationship, and your database cannot create a foreign key constraint with a delete cascade for such relationships (as the error message indicates).

    I suspect that your current migration still has DeleteBehavior.Restrict enabled which causes the error on applying the migration. Everytime you change the DeleteBehavior, you need to update your migration (remove the old one, and (re)create a new one).

    Can you post the generated migration code?