Setting a navigation ID property to null deletes the entity with that property
See original GitHub issueI’m going through the process of trying to upgrade from .NET 3.1 to .NET 6. I’ve managed to get everything building and have upgraded various NuGet packages across my solution.
After trying to run my unit tests, I am encountering some strange problems with some EF operations. I am using the In-memory database provider for these unit tests.
I have a set-up similar to the following:
Entities:
public class EntityA
{
public Guid Id { get; set; }
public Guid? EntityBId { get; set; }
public EntityB EntityB { get; set; }
}
public class EntityB
{
public Guid Id { get; set; }
public string Name { get; set; }
}
Configurations:
public class EntityAConfiguration: IEntityTypeConfiguration<EntityA>
{
public void Configure(EntityTypeBuilder<EntityA> builder)
{
builder.ToTable("EntitiyAs");
builder.Property(e => e.Id)
.HasColumnName("EntitiyAId")
.IsRequired();
builder.HasKey(e => e.Id)
.HasName("PK_EntityAs");
builder.HasIndex(e => e.EntityBId)
.HasName("IX_EntityAs_EntityBId");
builder.HasOne(e => e.EntityB)
.WithMany()
.HasForeignKey(e => e.EntityBId)
.HasConstraintName("FK_EntityA_EntityBs_EntityBId");
}
}
public class EntityBConfiguration: IEntityTypeConfiguration<EntityB>
{
public void Configure(EntityTypeBuilder<EntityB> builder)
{
builder.ToTable("EntityBs");
builder.Property(e => e.Id)
.HasColumnName("EntityBId")
.IsRequired();
builder.HasKey(e => e.Id)
.HasName("PK_EntityBs");
}
}
Creating my test DBContext like this:
private TestDbContext GenerateDbContext()
{
var options = new DbContextOptionsBuilder<TestDbContext>()
.UseInMemoryDatabase(Guid.NewGuid().ToString())
.EnableSensitiveDataLogging()
.Options;
return new TestDbContext(options);
}
In my tests, I am pre-populating a few of these entities in the DbContext before executing the method I want to test. The method under test looks like this:
public async Task RemoveEntityBFromAssociatedEntityA(Guid entityBId)
{
var entityB = await _dbContext.EntityBs.SingleOrDefaultAsync(g => g.Id == entityBId);
if (entityB == null)
{
// throw exception...
}
var entityA = await _dbContext.EntityAs.SingleOrDefaultAsync(s => s.EntityBId == entityB);
if (entityA == null)
{
// throw exception...
}
entityA.EntityBId = null;
_dbContext.entityAs.Update(entityA);
await _dbContext.SaveChangesAsync();
}
What I am doing here is removing the association to EntityB
on EntityA
by setting the navigation ID to null. Strangely, the effect this has is that EntityA
is marked for deletion when it’s EntityBId
is set to null and when SaveChanges
is called, it does infact delete EntityA
.
This doesn’t make a whole lot of sense to me. Why would EntityA
get deleted in this scenario? I’ve looked through the breaking changes in both EF Core 5 and EF Core 6 but I can’t see anything that would cause this.
I have tried switching the In-memory provider out for Sqlite but This exhibits the same strange behaviour.
Provider and version information
EF Core version: 6.0.0 Database provider: Microsoft.EntityFrameworkCore.InMemory and Microsoft.EntityFrameworkCore.Sqlite (both version 6.0.0) Target framework: . NET 6.0 Operating system: Windows 10 IDE: Rider 2021.3.1
Issue Analytics
- State:
- Created 2 years ago
- Comments:5 (3 by maintainers)
Yes. If either the FK or the nav to principal is non-nullable then the relationship is required
Thanks guys. You’ve cleared this up for me. I was pretty confused when this broke after upgrading but it makes sense now. I have made the appropriate changes to accommodate this default behaviour so please feel free to close this ticket.