Multi-tenancy in EF6 with multiple schemas having the same tables

.net c# entity-framework entity-framework-6 sql-server


In our system it has become required to provide a multi-tenant solution, where each tenant has the same data structure.

During investigation I came across an article discussing multi-tenancy with EF4.1.

This looks like a sensible solution, but we would prefer to avoid multiple database contexts if possible.

Also, we have a large number of migrations for our current single tenant solution. With EF6, it is possible for a migration to target a specific context and when none is supported, a default is targeted.

I have a couple of quesions here:

  1. Is there a better approach to multi-tenancy when using EF6 other than that specified for EF4?
  2. Is there a better way to handle the migrations?

Any help is much appreciated!

8/4/2014 12:19:45 PM

Accepted Answer

  1. Context is connecting to a connection string, if the connection string is resolved at runtime, then you are using One dbcontext class with httprequest specific instance. to distinguish httprequest, host name headers can be used.
  2. There is no easy way to handle migration. This is a complex question, but in short, before the end of release 1, i normally create a initial migration with all scripts to provision the database, this is to help the database created after this change it not effected by any migrations down the track. and then add migration every time i need to change it. let me know if more details needed.
8/13/2014 10:56:39 AM

Popular Answer

I understand this is old, however it's still widely searched topic.

I have used the following methods successfully with having multi-tenant by schema, using Code-First or DB First using EDMX.

  1. DB First (EDMX) - Edit the three sections that make up your EDMX; SSDL, CSDL, and C-S.
    • Remove any references to the Schema by replacing the schema name with nothing.
  2. Implement IDbCommandInterceptor and include command.CommandText = command.CommandText.Replace("<unwanted-schema-here>", "<your-actual-schema>") under all the *Executing implementations. Then Remove and Add the Interceptor before initializing a new context.

Example: Place your factory method inside a Partial class of your DbContext.

Private Shared _lschema As String
Public ReadOnly Property schema As String = _lschema

Public Shared Function GetContext(Optional connString As String = Nothing) As MyContext
   If connString IsNot Nothing Then
     Dim conn As EntityConnection = ContextHelper.CreateConnection(Of MyContext)(connString,ByRef _lschema) 
     DbInterception.Remove(New SchemaInterceptor)

     DbInterception.Add(New SchemaInterceptor(_lschema))
     Dim ctx = New MyContext(conn, False)
     ctx.Configuration.LazyLoadingEnabled = False
     ctx.Configuration.AutoDetectChangesEnabled = True

     Return ctx
   End If
   Return New MyContext()
End Function
  1. Work to build your own model dynamically, using IDbModelCacheKeyProvider, this is used in a similar method as the example above. Such as building your connection by calling a method that gets the schema of the connection and returning it.

Related Questions


Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow