Julian Wilson
Julian Wilson

Reputation: 2470

Entity Framework delete related entry instead of setting to null FK

I have this model (simplified):

public class Request
{
    [Key]
    public int Id { get; set; }
    public virtual StructuredNote Response { get; set; }
}

And each StructuredNote has a List<CallSchedComp> like this:

public class StructuredNote
{
    public virtual List<CallSchedComp> CallSchedule { get; set; }
}

I want to update a particular Request's CallSchedule. The issue is often I need to completely regenerate the CallSchedule, not modify the existing referenced CallSchedule. When regenerating a completely new List<CallSchedComp>, obviously the pointer is new now and hence what ends up happening when I do something like:

request.Response.CallSchedule = NewCallScheduleWithNewPointer;
_ctxt.Entry(request).State = EntityState.Modified;

Is that EF sets the FKs on the existing CallSchedComps part of the List<CallSchedule>to nullinstead of deleting them from the database. The new CallSchedComp's have the correct FK pointing to the Response. I believe this is the default EF behavior, right?

My questions:

  1. Is there a way to remove the old List<CallSchedComp> in the database instead of just setting its foreign key to null?
  2. Should I even bother with this if it doesn't affect performance?

Hopefully it's clear. Thanks!

EDIT: As per request:

 public class CallSchedComp
{
    [Key]
    public int CallSchedCompId { get; set; }

    [Range(typeof(DateTime), "1/1/1900", "6/6/2079")]
    public DateTime ObservationDate { get; set; }

    [Range(typeof(DateTime), "1/1/1900", "6/6/2079")]
    public DateTime PaymentDate { get; set; }
    public decimal Coupon { get; set; }
    public decimal Strike { get; set; }
    public OptionType OptionType { get; set; }
    public CallType CallType { get; set; }
    public decimal CallPrice { get; set; }
    public decimal AutoCallLevel { get; set; }
    public decimal UpsideStrike { get; set; }
    public decimal UpsideParticipation { get; set; }
    public bool ExcessParticipationOnAutoCallOnly { get; set; }

    public virtual StructuredNote IncomeNote { get; set; }

    [Timestamp]
    public byte[] Timestamp { get; set; }
}

And the very basic fluentAPI configurations. I've used almost entirely annotations to configure the relationship.

        modelBuilder.Entity<CallSchedComp>().Property(x => x.AutoCallLevel).HasPrecision(18, 4);
        modelBuilder.Entity<CallSchedComp>().Property(x => x.CallPrice).HasPrecision(18, 4);
        modelBuilder.Entity<CallSchedComp>().Property(x => x.Coupon).HasPrecision(18, 4);
        modelBuilder.Entity<CallSchedComp>().Property(x => x.Strike).HasPrecision(18, 4);
        modelBuilder.Entity<CallSchedComp>().Property(x => x.UpsideParticipation).HasPrecision(18, 4);
        modelBuilder.Entity<CallSchedComp>().Property(x => x.UpsideStrike).HasPrecision(18, 4);

Upvotes: 0

Views: 1197

Answers (1)

Ivan Stoev
Ivan Stoev

Reputation: 205599

Here is the case. In CallSchedComp class you have only navigation property IncomeNote, but no explicit FK property, no data annotations and no fluent configuration for the relationship. Thus, by convention the many side of the relationship is optional (with nullable FK) and with cascade behavior, which EF processes the way you describe - by setting the FK column to null.

The only way to let EF cascade delete the related records in to make the IncomeNote required:

modelBuilder.Entity<CallSchedComp>()
    .HasRequired(e => e.IncomeNote)
    .WithMany(e => e.CallSchedule)
    .WillCascadeOnDelete();

Upvotes: 1

Related Questions