Search code examples
c#entity-framework

Entity Framework : creating a reference to an object from a collection


I am trying to create an entity which at the same time contains a collection of child entities and a reference to a single entity (let's call it Current) from this collection:

public class Parent
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int? Id { get; set; } = null;
    public virtual ICollection<Child> Children { get; set; }
    public virtual Child Current { get; set; }
    //Some fields
    
    public Parent()
    {
        Child child1 = new Child();
        Child child2 = new Child();
        Children = [child1, child2];
        Current = child1;
    }
}

public class Child
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int? Id { get; set; } = null;
    //Some fields
}

As soon as children can have only one parent, I'd ideally like to set DeleteBehavior.Cascade.

But I can't figure out a correct configuration for this relationship:

I either get a runtime error

Unable to save changes because a circular dependency was detected in the data to be saved

or something like

Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.

Is it even possible with EF and, if so, how to correctly configure this relationship?


Solution

  • Yes, it’s possible. You need to use two separate foreign keys and configure one of them without cascading deletes to avoid circular references.

      public class Parent
    {
        public int Id { get; set; }
        public ICollection<Child> Children { get; set; }
        public int? CurrentId { get; set; }
        public Child Current { get; set; }
    }
    
    public class Child
    {
        public int Id { get; set; }
        public int ParentId { get; set; }
        public Parent Parent { get; set; }
    }
    
    modelBuilder.Entity<Parent>()
        .HasMany(p => p.Children)
        .WithOne(c => c.Parent)
        .HasForeignKey(c => c.ParentId)
        .OnDelete(DeleteBehavior.Cascade);
    
    modelBuilder.Entity<Parent>()
        .HasOne(p => p.Current)
        .WithMany()
        .HasForeignKey(p => p.CurrentId)
        .OnDelete(DeleteBehavior.Restrict);
    

    This setup allows a parent to have a collection of children and a single “Current” child, while avoiding circular dependency errors.