Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EF Core Dependents not deleted when severed from parent in optional relationship even with Delete Behavior Configured

I have my entities configured for optional one to many relationship using PropertyAccessMode.Field mode to make things happen in DDD way. I'm loading parent entity along with two child. Now I'm removing one child from parent and save it. To my surprise, I can see EF setting NULL in child table column for foreign key. I then searched through docs and found in this section Optional relationship with dependents/children loaded that Delete Behavior needs to be set so that dependents will be deleted by EF Core on severe but still EF Core is not deleting the child instead it sets NULL in foreign key field.

image

This issue happens only with optional relationship. If I make the below code to have required relationship EF is deleting the child as expected with the same code. Just that I need to mark relationship as required and do changes in table to make Foreign Key column as NOT NULL.

image

EF Core Details:

EF Core version: 7.0.3

Database provider: Microsoft.EntityFrameworkCore.SqlServer

Target framework: .NET 6.0

Code Sample:

using (var context = new EFDbContext())
{
    var orderItems = new List<OrderItem> { new OrderItem ("one"), new OrderItem ("two") };
    var order = new Order("Test", orderItems);
    context.Orders.Add(order);
    context.SaveChanges();
}

using (var context = new EFDbContext())
{
    var order = context.Orders.Include(x => x.OrderItems).FirstOrDefault();
    order.RemoveOrderItem(order.OrderItems[0]);
    context.Orders.Update(order);
    context.SaveChanges();
}

public class EFDbContext : DbContext
{
    public DbSet<Order> Orders { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer("Data Source=localhost;Initial Catalog=Test;User Id=sa;Password=xxxx;TrustServerCertificate=true");
        optionsBuilder.LogTo(Console.WriteLine);
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Order>(entity =>
        {
            entity.ToTable("Order");
            entity.HasKey(x => x.Id);

            entity.HasMany(order => order.OrderItems)
                   .WithOne()
                   .IsRequired(false)
                   .OnDelete(DeleteBehavior.ClientCascade)
                   .Metadata.PrincipalToDependent.SetPropertyAccessMode(PropertyAccessMode.Field);
        });

        modelBuilder.Entity<OrderItem>(entity =>
        {
            entity.ToTable("OrderItem");
            entity.HasKey(x => x.Id);
        });
    }
}

public class Order
{
    private readonly List<OrderItem> _orderItems = new();

    private Order() { }

    public Order(string name, List<OrderItem> orderItems)
    {
        Name = name;
        _orderItems = orderItems;
    }

    public Guid Id { get; set; }
    public string Name { get; set; }

    public IReadOnlyList<OrderItem> OrderItems => _orderItems.ToList();

    public void RemoveOrderItem(OrderItem orderItem)
    {
        _orderItems.Remove(orderItem);
    }
}

public class OrderItem
{
    private OrderItem() { }

    public Guid Id { get; set; }
    public string Name { get; set; }

    public OrderItem(string name)
    {
        Name = name;
    }
}

Please assist me if I'm missing something.

like image 962
fingers10 Avatar asked Oct 14 '25 09:10

fingers10


1 Answers

I found the same question asked (and answered) on Github by the EF Core team. It's because from EF Core 7.0 onwards, orphaned dependents of optional relationships are no longer deleted by default according to https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-7.0/breaking-changes?tabs=v7#optional-deletes

like image 190
Casper Avatar answered Oct 16 '25 23:10

Casper