OnModelCreating only called once even for new contexts
Asked Answered
L

3

7

I have multiple SQL server tables that are the same, but differ in content. In writing a code first EF6 program I am trying to reuse the same db context for each and pass in the table name to the context constructor.

However, while the constructor is being called every time, the OnModelCreating method is only being called once despite the db context being created from new every time. How do I reset this?

I have tried using AsNoTracking and I read along the lines of disabling ModelCaching but couldn't find out how to do this or whether this was the best approach. MSDN even says 'this caching can be disabled by setting the ModelCaching property on the given ModelBuidler[sic],' but it's not there.

This is my DB Context:

public partial class MissingContext : DbContext
{
    private string tableName = "";
    public MissingContext(string tableName) : base("name=MissingContext")
    {
        this.tableName = tableName;
    }

    public virtual DbSet<MissingData> MissingDataSet { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<MissingData>()
           .ToTable(this.tableName);
    }
}

This is my code to use it:

List<MissingData> missingData=null;
string[] inputTables="TABLEA;TABLEB;TABLEC".Split(';');
foreach (string table in inputTables)
{
    logger.Info($"Processing {table}");
    missingData = null;

    MissingContext db = new MissingContext(table);
    var query = from d in db.MissingDataSet.AsNoTracking()
                select d;
    missingData = query.ToList();
}

In running, table always has the correct TABLEA, TABLEB, TABLEC and it is passed in to the db context constructor, however the OnModelCreating is only called once for the very first loop item so the SQL generated by the query object always selects from TABLEA:

SELECT 
[Extent1].[id] AS [id], 
[Extent1].[OrganisationName] AS [OrganisationName] 
FROM [dbo].[**TABLEA**] AS [Extent1]

*apologies if any code looks wrong, I rename some variables as they are business sensitive.

Landis answered 8/3, 2018 at 14:14 Comment(0)
B
5

OnModelCreating will be called only once that's default behaviour.

According to OnModelCreating documentation.

Typically, this method is called only once when the first instance of a derived context is created. The model for that context is then cached and is for all further instances of the context in the app domain. This caching can be disabled by setting the ModelCaching property on the given ModelBuidler, but note that this can seriously degrade performance. More control over caching is provided through use of the DbModelBuilder and DbContextFactory classes directly.
Briony answered 9/3, 2018 at 14:38 Comment(1)
indeed. still found a workaround here https://mcmap.net/q/904625/-dynamically-changing-schema-in-entity-framework-coreEudo
W
0

I think the issue here is that per-table is not how contexts are designed to be created.
The design of Entity Framework is that (in the most general case), each table will have one class expressing any row in that table. For a different table, it is expected that another class will be defined. Then, you have your derived DbContext.
One DbContext may service arbitrarily many tables, by creating the appropriate DbSet for each of your table classes. If you desire them to work in different contexts for some reason, the design of EF would expect a different class derived from DbContext with it's own DbSets.
A caveat: If you're connecting to merely different databases with the same tables, meaning the columns exactly correspond etc., you can use the same DbContext, supplying the constructor with differing connection strings as appropriate.

Wira answered 9/3, 2018 at 15:25 Comment(2)
thanks. maybe I need a different approach. I would have thought my problem was not unique...Landis
I tried using a different connection string, however, the DbContext instance is still just created onceAnis
F
0

I got it working with overriding DbContext.OnConfiguring:

  protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
  {  
     base.OnConfiguring(optionsBuilder);
     optionsBuilder.EnableServiceProviderCaching(false);
  }

My situation that I could solve that way was like this:

EF Core 6, XUnit, SQLite in-memory, one Test class, two Test methods running sequentially.

When running both Test methods in one single run in the Visual Studio TestRunner, DbContext.OnModelCreating was called only in the first Test method, not in the second.

When running the Test methods individually or in different order, same effect, it was independent from which Test method was executed first.

Frayne answered 19/9, 2024 at 17:10 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.