Home > Back-end >  EF Core Remove Reference to Self without deleting
EF Core Remove Reference to Self without deleting

Time:10-11

I have a class that references itself as a chain of 'equivalent versions'; however once set, I am unable to clear this reference down the line.

public class Foo
{
   public int FooId { get; set; }
   public string Name { get; set; }
   public virtual Foo EquivalentFoo { get; set; }

   public static void RunFluent(ModelBuilder modelBuilder)
   {
     EntityTypeBuilder<Foo> entity = modelBuilder.Entity<Foo>();
     entity.HasKey(f => f.FooId);
     entity.HasOne(f => f.EquivalentFoo).WithMany().IsRequired(false);
   }
}

My controller for this has the following update endpoint:

[HttpPut("{id}")]
public async Task<IActionResult> PutFoo(int id, Foo foo)
{
    ...

    _context.Entry(foo).State = EntityState.Modified;

    if (foo.EquivalantFoo != null)
    {
        _context.Entry(foo.EquivalantFoo).State = EntityState.Unchanged;
    }

    try
    {
        await _context.SaveChangesAsync();
    }
    catch (DbUpdateConcurrencyException ex)
    {
        ...
    }

    return NoContent();
}

This works fine to add a new EquivalentFoo to one that doesn't have one, or change it to a new Foo.

What I'm struggling with is passing a foo with EquivalentFoo = null. Even though EquivalentFoo is nullable and the database is fine with null keys, the foreign key column that EF Core has generated is not updated to show null. It doesn't even throw an error, it just doesn't update.

Note that in this case, I don't actually want to delete any of these Foos from the database. All that should happen is the Foo being updated should now have a null key referencing any EquivalentFoos.

CodePudding user response:

According to the documentation, setting State to Modified should set all all properties (including shadow) to modified as well.

However as you already observed, shadow FK properties with null value (and corresponding reference navigation property being null at the same time) seem to have special treatment, in particular not marked as modified by the aforementioned operation (same if you use Update method).

So you need to force EF Core to update FK property by manually marking it as modified using the ReferenceEntry returned by the Reference method, e.g.

//...
var entry = _context.Entry(foo);
entry.State = EntityState.Modified;
entry.Reference(e => e.EquivalentFoo).IsModified = true; // <--
//...

CodePudding user response:

notice the "?" mark on ParentFooRefno, this will let you add null values

    public class Foo
    {
       [Key,DatabaseGenerated(DatabaseGeneratedOption.Identity)]
       public int FooId { get; set; }
       public string Name { get; set; }

       public int? ParentFooRefno { get; set; }
       
       [ForeignKey("ParentFooRefno ")]
       public virtual Foo EquivalentFoo { get; set; }
    
        
    }
  • Related