efcore icon indicating copy to clipboard operation
efcore copied to clipboard

EntityBuilder: .OnDelete() is ignored if used after .IsRequired() and shadow property

Open pascal-910 opened this issue 4 years ago • 2 comments
trafficstars

Problem

When configuring a non-nullable foreign key with FluentAPI .OnDelete() is ignored when called after .IsRequired() but only if no explicit foreign key is configured for relationship in dependant entity. If I'd add a AddressId property in Order model it would work as expected.

Code

Model

  public class Address {
      public int AddressId { get; set; }
  }

  public class Order {
      public int OrderId { get; set; }
      public Address Address { get; set; }
  }

FluentAPI Case 1) Does work: DeleteBehavior: No Action is taken (see debug output below) Case 2) Doesn't work: Default behavior Cascade is taken (see debug output below)

  protected override void OnModelCreating(ModelBuilder modelBuilder)
  {
      // 1) Does work
      modelBuilder.Entity<Order>()
          .HasOne(o => o.Address)
          .WithOne()
          .HasForeignKey<Order>("AddressId")
          .OnDelete(DeleteBehavior.NoAction)
          .IsRequired();

      // 2) Doesn't work
      modelBuilder.Entity<Order>()
          .HasOne(o => o.Address)
          .WithOne()
          .HasForeignKey<Order>("AddressId")
          .IsRequired()
          .OnDelete(DeleteBehavior.NoAction);
  }

Debug ShortView Case 1

Model: 
  EntityType: Address
    Properties: 
      AddressId (int) Required PK AfterSave:Throw ValueGenerated.OnAdd
    Keys: 
      AddressId PK
  EntityType: Order
    Properties: 
      OrderId (int) Required PK AfterSave:Throw ValueGenerated.OnAdd
      AddressId (no field, int) Shadow Required FK Index
    Navigations: 
      Address (Address) ToPrincipal Address
    Keys: 
      OrderId PK
    Foreign keys: 
      Order {'AddressId'} -> Address {'AddressId'} Unique ToPrincipal: Address
    Indexes: 
      AddressId  Unique

Case 2

Model: 
  EntityType: Address
    Properties: 
      AddressId (int) Required PK AfterSave:Throw ValueGenerated.OnAdd
    Keys: 
      AddressId PK
  EntityType: Order
    Properties: 
      OrderId (int) Required PK AfterSave:Throw ValueGenerated.OnAdd
      AddressId (no field, int) Shadow Required FK Index
    Navigations: 
      Address (Address) ToPrincipal Address
    Keys: 
      OrderId PK
    Foreign keys: 
      Order {'AddressId'} -> Address {'AddressId'} Unique ToPrincipal: Address Cascade
    Indexes: 
      AddressId  Unique

Maybe also see a similar yet fixed issue #23555, but it was the other way around (.IsRequired didn't work after .OnDelete)

EF Core version: 5.0.7 Database provider: Microsoft.EntityFrameworkCore.SqlServer / Microsoft.EntityFrameworkCore.SQlite / ... ? Target framework: NET 5.0 Operating system: Win10.0.19042.1052 IDE: Visual Studio 2019 CE 16.10

pascal-910 avatar Jul 02 '21 07:07 pascal-910

The issue is still present. https://github.com/dotnet/efcore/blob/289e7a69b0c02f5569bbaf0ac353c21afde5e397/src/EFCore/Metadata/Internal/ForeignKey.cs#L687-L689

When changing required, the convention return new Fk to change deletebehavior to cascade but we don't pick up new FK and hence DeleteBehavior is applied on stale fk and lost.

smitpatel avatar Sep 27 '21 18:09 smitpatel

We need to start a convention batch and track the FK when the conventions need to run

AndriySvyryd avatar Sep 28 '21 15:09 AndriySvyryd