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.

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.

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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With