Noel
Noel

Reputation: 600

How does EF Core build its internal model?

Background: We're doing an annoying merge due to a poor branching strategy. Note: all code is pseudocode

We updated an entity class to change the Submittal table. We removed the specific report Id and it's foreign key and replaced it with a generic 'ReportId' with no foreign key.

public class Submittal{
  int Id {get;set}
  string Status {get;set;}
  int SpecificReportId {get;set}
}  

There were some migrations that were applied that changed the db (db has the updated column and no FK) The db context has no reference to the old column. The entity now looks like:

public class Submittal{
  int Id {get;set}
  string Status {get;set;}
  int ReportId {get;set}
}

The modelBuilder in the context has no reference to the old column name. The model snapshot with the migrations has no reference to the old column name.

The repository method for adding the submittal:

public async Task AddSubmittal(Submittal submittal){
  using var context = new ReportContext(dbContextOptions);
  context.Add(model);
  context.SaveChangesAsync();
}

When debugging, the submittal object has ReportId and no SpecificReportId, but when it tries to run SaveChangesAsync() it fails with an exception of "SqlException: Invalid column name 'SpecificReportId'.".

The dbOptions connection string is pointing at the database I expect, and when I ran sql profiler I got the following sql for my query:

INSERT INTO [Schema].[Submittal] ([Status], [SpecificReportId], [ReportId])
VALUES (@p0, @p1, @p2);
SELECT [Id]
FROM [Schema].[Submittal]
WHERE @@ROWCOUNT = 1 AND [Id] = scope_identity();

What the heck is going on? It feels like I must have missed some piece of how the internal model is generated. I have searched the code for the original id, but did not see anything that looked related.

Upvotes: 0

Views: 71

Answers (1)

huancz
huancz

Reputation: 375

Notice that the query is trying to insert both ReportId and SpecificReportId. That means you have some lost (or inherited) public SpecificReport SpecificReport { get; set; } inside Submittal class (or opposite reference in SpecificReport class), and EF creates shadow foreign key for it. Full dump of what EF knows about your model is available in DbContextModelSnapshot.cs file, updated with each migration (try adding new migration and make sure it's generated as empty, before you rely on it).

Your pseudocode should work as posted, there must be something else in your project.

PS: you can also set Microsoft.EntityFrameworkCore.Database.Command log level to information, as another debugging tool.

Upvotes: 1

Related Questions