Entity Framework Code First return same data for different tables mapped to the same class

I have a class Timer

that I want to use with different tables that have the same structure, so I am passing in the table name.

public class TimerContext : DbContext
{
    public DbSet<Timer> Timers { get; set; }

    private readonly string _tableName;

    public TimerContext(string tableName) : base("name=fooDb")
    {
        _tableName = tableName;
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Timer>().ToTable(_tableName);

        base.OnModelCreating(modelBuilder);
    }
}

      

However, when I pass in two different table names, they return the same data. prevTimers

contains the same data as currTimers

. How do I get unique data from each table? Why am I getting the same data for two different tables?

var currTimers = new TimerContext(currentTimerTableName).Timers.ToList();
var prevTimers = new TimerContext(previousTimerTableName).Timers.ToList();

      

0


source to share


2 answers


EF will call the OnModelCreating method to create an in-memory copy as needed. Once this is done, this copy will be used. In your case, the code to generate prevTimers uses this in-memory model that maps to the current timer table. If you put a breakpoint in the OnModelCreating method, you will see that it is called only once.

All that has been said, it is possible to comment out and poll the model in memory (you must use the old school context type, ObjectContext and DbContext). Using some code from Rowan Miller here , you can find which table maps to each set of objects. Using this code, each item in a table variable has a Read / Write property that contains the name of the database table. I haven't tried to install this, but it certainly seems plausible. Of course, you will need to modify the model somewhere else outside of the OnModelCreating method, say in the constructor, so that the code will fire every time the context is instantiated.

* UPDATE *



Because I'm always interested in learning new things, I couldn't leave this alone and ditched the test application. Unfortunately, it looks like you cannot set the property (despite being a read / write property), as it throws an InvalidOperationException stating that the element is read-only. Maybe there is another way, but I haven't found it yet ...

* UPDATE *



The solution is actually much simpler than what I first mentioned. A pair of constructors for the DbContext class takes an instance of the DbCompiledModel class as one of its parameters. Using the DbModelBuilder class, you can create the same code that you would normally add to the OnModelCreating method. You can call the Build method of this class to instantiate the DbModel class. You can call the compilation method of this class to instantiate the DbCompiledModel class. The only real trick is that the Build method requires additional information (I used an instance of the DbProviderInfo class, but I think you can use an actual connection as well, but that will probably end up hitting the database). I've tested this and it actually works as desired.

Something like...

DbModelBuilder builder = null;

builder = new DbModelBuilder();
builder.Entity<TestEntity>().ToTable(tableName);

DbModel model1 = null;

model1 = builder.Build(new DbProviderInfo("System.Data.SqlClient", "2012"));

builder.Entity<TestEntity>().ToTable(anotherTableName);

DbModel model2 = null;

model2 = builder.Build(new DbProviderInfo("System.Data.SqlClient", "2012"));

DbCompiledModel compiledModel1 = null;
DbCompiledModel compiledModel2 = null;

compiledMdoel1 = model1.Compile();
compiledMdoel2 = model2.Compile();

TestContext context1 = null;
TestContext context2 = null;

context1 = new TestContext(compiledModel1);
context2 = new TestContext(compiledModel2);

      

Of course, the constructor of the TestContext class must pass an instance of the compiled model to the base constructor.

+3


source


can't add a comment, but I just want to add one thing that happened to me

my code was like this:

DbModelBuilder builder = new DbModelBuilder();
this.OnModelCreating(builder);
var model = builder.Build(this.Database.Connection);

      



I thought that when I pass the current DbConnection object to this method, it somehow "inherits" all the connection settings, but I guess I was wrong. After some debugging, I just realize that some strange connection string is being generated for it, which always results in not being able to find a database problem. So my solution is to instantiate "TestContext" (as in Jason Richmeier's answer ), pass the nameOrConnectionString as the first parameter, and the compiled model as the second, and it solved my problem.

Interesting, since EF keeps a copy of a certain model in memory, manually creates another, just creates a new copy in memory? And if my code has to do this many times, will it keep creating new models in memory and finally end up with a memory overflow?

0


source







All Articles