How to change Entity Framework context db model cache at runtime

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/

Advertisements