Skip to content

Setting a Nullable Foreign Key property to Null triggers cascade delete #27174

@failwyn

Description

@failwyn

Using Entity Framework Core 6.0.1

The following code should create a Module model with the HelpCard Foreign Key set, then set the Help Card Foreign Key to Null and save the model to the database, but instead the Cascade Delete is being triggered and the record is deleted from the database. This worked fine in Entity Framework Core 5;

Removing .OnDelete(DeleteBehavior.Cascade) from either of the Configurations does not affect this behavior; removing it from both of the Configurations makes it behave as expected (but I need the Cascade).

Edit: Nullable Reference Types are set to Disable for the project, according to documentation, this should maintain the existing behavior.

// create a model with the ForeignKey set
var m = new Models.Module() {
        Name = "Test",
        HelpCardId = DatabaseContext.HelpCard.Select(r => r.Id).First()
    };
    DatabaseContext.Add(m);
    DatabaseContext.SaveChanges(true);
    
    // set the ForeignKey to null
    m.HelpCardId = null;
    // the model state is now marked as Deleted
    var state = DatabaseContext.Entry(m).State;
    // after saving, the record is deleted from the database instead of being saved with the ForeignKey set to Null
    DatabaseContext.SaveChanges(true);

Models

public partial class Module : Entity, IEntity<Guid>
{
    private HelpCard _HelpCard;

    public Module()
    {
    }

    private Module(ILazyLoader lazyLoader) : this()
    {
        LazyLoader = lazyLoader;
    }

    private ILazyLoader LazyLoader { get; set; }

    [Key]
    [Required()]
    public virtual Guid Id { get; set; }

    [StringLength(100)]
    [Required()]
    public virtual string Name { get; set; }

    public virtual Guid? HelpCardId { get; set; }        

    public virtual HelpCard HelpCard
    {
        get
        {
            return LazyLoader?.Load(this, ref _HelpCard);
        }
        set
        {
            this._HelpCard = value;
        }
    }                
}
public partial class HelpCard : Entity, IEntity<Guid>, ICloneable 
{
    private IList<Module> _Modules;

    public HelpCard()
    {
        this._Modules = new List<Module>();
    }

    private HelpCard(ILazyLoader lazyLoader) : this()
    {
        LazyLoader = lazyLoader;
    }

    private ILazyLoader LazyLoader { get; set; }

    [Key]
    [Required()]
    public virtual Guid Id { get; set; }

    [StringLength(100)]
    [Required()]
    public virtual string Name { get; set; }

    public virtual IList<Module> Modules
    {
        get
        {
           return LazyLoader?.Load(this, ref _Modules);
        }
        set
        {
            this._Modules = value;
        }
    }
}

Configuration

public partial class ModuleConfiguration : IEntityTypeConfiguration<Module>
{
    public void Configure(EntityTypeBuilder<Module> builder)
    {
        builder.ToTable(@"Module", @"dbo");
        builder.Property(x => x.Id).HasColumnName(@"Id").HasColumnType(@"uniqueidentifier").IsRequired().ValueGeneratedOnAdd().HasDefaultValueSql(@"newid()");
        builder.Property(x => x.Name).HasColumnName(@"Name").HasColumnType(@"varchar(100)").IsRequired().ValueGeneratedNever().HasMaxLength(100);
        builder.Property(x => x.HelpCardId).HasColumnName(@"HelpCardId").HasColumnType(@"uniqueidentifier").ValueGeneratedNever();
        builder.HasKey(@"Id");
        builder.HasOne(x => x.HelpCard).WithMany(op => op.Modules).OnDelete(DeleteBehavior.Cascade).HasForeignKey(@"HelpCardId").IsRequired(false);          

        CustomizeConfiguration(builder);
    }
}
public partial class HelpCardConfiguration : IEntityTypeConfiguration<HelpCard>
{
    public void Configure(EntityTypeBuilder<HelpCard> builder)
    {
        builder.ToTable(@"HelpCard", @"dbo");
        builder.Property(x => x.Id).HasColumnName(@"Id").HasColumnType(@"uniqueidentifier").IsRequired().ValueGeneratedOnAdd().HasDefaultValueSql(@"newid()");
        builder.Property(x => x.Name).HasColumnName(@"Name").HasColumnType(@"varchar(100)").IsRequired().ValueGeneratedNever().HasMaxLength(100);
        builder.HasKey(@"Id");
        builder.HasMany(x => x.Modules).WithOne(op => op.HelpCard).OnDelete(DeleteBehavior.Cascade).HasForeignKey(@"HelpCardId").IsRequired(false);

        CustomizeConfiguration(builder);
    }
}

EF Core version: 6.00 & 6.01
Database provider: Microsoft.EntityFrameworkCore.SqlServer
Target framework: .NET 6.0
Operating system: Windows 10
IDE: Visual Studio 2022 17.0.2

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions