Closed vegov closed 11 months ago
@vegov I am not able to reproduce this--see my code below. Please attach a small, runnable project or post a small, runnable code listing that reproduces what you are seeing so that we can investigate.
using (var context = new SomeDbContext())
{
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();
context.Add(new DamagesPayment { DamageNo = "X", PaymentFile = new() { FileName = "X" } });
await context.SaveChangesAsync();
}
using (var context = new SomeDbContext())
{
var damageNumbers = new List<string> { "X", "Y" };
var demo = await context.DamagesPayments
.Include(x => x.PaymentFile)
.Where(x => damageNumbers.Contains(x.DamageNo))
.ToListAsync();
context.SaveChanges();
}
public class SomeDbContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseSqlServer(@"Data Source=(LocalDb)\MSSQLLocalDB;Database=AllTogetherNow")
.LogTo(Console.WriteLine, LogLevel.Information)
.EnableSensitiveDataLogging();
public DbSet<DamagesPayment> DamagesPayments => Set<DamagesPayment>();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<DamagesPayment>(entity =>
{
entity.ToTable("DamagesPayments", "dbo");
entity.HasOne(x => x.PaymentFile)
.WithOne()
.HasForeignKey<DamagesPayment>(x => x.IncludeInPaymentFile)
.HasPrincipalKey<DamagesPaymentFile>(x => x.FileName)
.IsRequired(false)
.OnDelete(DeleteBehavior.Restrict);
});
modelBuilder.Entity<DamagesPaymentFile>(entity => { entity.ToTable("DamagesPaymentFiles", "dbo"); });
}
}
public class DamagesPayment
{
public Guid Id { get; set; }
public string DamageNo { get; set; }
public byte DamageReportNo { get; set; }
public string? IncludeInPaymentFile { get; set; }
public DamagesPaymentFile? PaymentFile { get; set; }
}
public class DamagesPaymentFile
{
public Guid Id { get; set; }
public DateTime? AccountingDate { get; set; }
public string FileName { get; set; }
}
The sad part is that when I take a bare bones example and connect it to our database, I can reproduce it. When I create a local database like you did, the error does not occur. So you can not reproduce it. Do you have any ideas why this might have happened? I scaffolded the two tables from our database using the dotnet ef scaffold command?
In short, the only difference in my code right now is the Connection string. Any ideas what I might be missing, so that I can reproduce it and give it back?
Soo I am happy to say that I wasted half a day to find was was wrong. The relation is configured as a 1:1. However, the actual relation in the database is 1:N. So when there is a second record containing the FK, EF Core decides to update and delete the foreign keys.
I was able to reproduce it. I have submitted a script for a demo database, and a script that should demonstrate the bug.
If you consider this not a bug, maybe add a warning when this happens or my humble opinion should be an exception. Almost lost half the prod database from this little bugger.
@vegov A fundamental tenet of EF Core is that it uses the model to work efficiently with the database. If we added checks where the data coming back doesn't match the model that would slow down data access for all the cases where the model is accurate. So we don't do this, but instead require that applications accurately map the model to the database.
Nice, your tenet is - "Screw your prod database, fast". Okay, acceptable.
File a bug
The bug is that I have two entities. They do not have a FK. However, I use includes in the select query and I use HasForeignKey as shown in the db context. The only thing I do is I do the select, do a save changes, as other tables different than DamagesPayment and DamagesPaymentFile need the save. On the save the EF Core does an update on the IncludeInPaymentFile which is specified as a foreign key. That is not expected. That column is never updated.
The issue is resolved if I mark the entities as detached if I use AsNoTracking in the query.
Include your code
Include stack traces
Include provider and version information
EF Core version: 6.0.4 Database provider: e.g. Microsoft.EntityFrameworkCore.SqlServer Target framework: e.g. .NET 6.0 Operating system: Windows 10 locally, Linux in prod