How to change Entity Framework context db model cache at runtime
05-Aug-1414 Leave a comment
I have two customer database tables, but want to use the same model and context, just be able to determine at runtime if i want to load from the live or the prospect customer table. The problem is that a context OnModelCreating runs only once by default, so you can’t leave parameters there to switch for you. One solution was to copy the context, but I found I needed a bit too much extra code in the usage to determine which to use. To understand a solution it is worth using the Visual Studio Object Browser DbContext remarks. “The protected OnModelCreating method can be overridden to tweak this model. More control over the model used for the Model First approach can be obtained by creating a System.Data.Entity.Infrastructure.DbCompiledModel explicitly from a System.Data.Entity.DbModelBuilder and passing this model to one of the DbContext constructors.” So you can create a DbCompliedModel (System.Data.Entity.Infrastructure) and store it if you may switch back to it, then use it to create an instance of your context. This can be done on the context using Shared / Static factory method.
Public Class CustomerContext Inherits DbContext Property Customers() As DbSet(Of Customer) Private Shared dbCompiledModelLive As DbCompiledModel Private Shared dbCompiledModelProspect As DbCompiledModel Private Sub New(connection As DbConnection, model As DbCompiledModel) MyBase.New(connection, model, True) End Sub Shared Function CreateCustomerContext(LiveCustomer As Boolean) As CustomerContext Dim conStr = ConfigurationManager.ConnectionStrings("BusinessEntities").ConnectionString Dim DbConnection As New SqlConnection(conStr) If LiveCustomer Then If dbCompiledModelLive IsNot Nothing Then Return New CustomerContext(DbConnection, dbCompiledModelLive) End If Else If dbCompiledModelProspect IsNot Nothing Then Return New CustomerContext(DbConnection, dbCompiledModelProspect) End If End If Dim modelBuilder As New DbModelBuilder CustomerMap.LiveCustomerFlag1 = LiveCustomer modelBuilder.Configurations.Add(New CustomerMap) Dim model = modelBuilder.Build(DbConnection) If LiveCustomer Then dbCompiledModelLive = model.Compile Return New CustomerContext(DbConnection, dbCompiledModelLive) End If dbCompiledModelProspect = model.Compile Return New CustomerContext(DbConnection, dbCompiledModelProspect) End Function End Class
This all works
<TestMethod()> _ Public Sub CustomersTest() Dim targetLive = CustomerContext.CreateCustomerContext(True) Dim actual As DbSet(Of Customer) = targetLive.Customers Debug.Print("Live Customers") PrintResult(actual) Assert.IsTrue(actual.Count > 2) Dim targetProspect = CustomerContext.CreateCustomerContext(False) actual = targetProspect.Customers Debug.Print("") Debug.Print("Prospect Customers") PrintResult(actual) Assert.AreEqual(0, actual.Count) actual = targetLive.Customers Debug.Print("") Debug.Print("Live Customers") PrintResult(actual) Assert.IsTrue(actual.Count > 2) targetLive = CustomerContext.CreateCustomerContext(True) actual = targetLive.Customers Debug.Print("") Debug.Print("Live Customers") PrintResult(actual) Assert.IsTrue(actual.Count > 2) End Sub Private Sub PrintResult(actual As DbSet(Of Customer)) For Each item As Customer In actual Debug.Print(String.Concat(item.ID, vbTab, item.Customer1)) Next End Sub
Could be useful With thanks also to: http://romiller.com/2011/05/23/ef-4-1-multi-tenant-with-code-first/