Out of the box there is no way, or at least not an easy one, to change table or schema names used by the Entity Framework at runtime. If you used MyDbName.dbo.BlogPosts as table name during development you can not use MyDbName.dbo.CustomerA_BlogPosts if you want to support customer specific table names as explained in my previous post.
On CodePlex however you can find an adapter for your Entity Framework model to change it at runtime. You can change the connection to the database, change table names or use different schemas. So a lot of goodness to support multi tenant applications.
In order to use the adapter you should create a partial class with the name of your context class and inherit from AdaptingContext instead of ObjectContext.
public partial class AdventureWorksEntities
: AdaptingObjectContext
{
public AdventureWorksEntities()
:base("name=AdventureWorksEntities", "AdventureWorksEntities",
new ConnectionAdapter(new TablePrefixModelAdapter("MyPrefix"), Assembly.GetExecutingAssembly()))
{
OnContextCreated();
}
} |
public partial class AdventureWorksEntities
: AdaptingObjectContext
{
public AdventureWorksEntities()
:base("name=AdventureWorksEntities", "AdventureWorksEntities",
new ConnectionAdapter(new TablePrefixModelAdapter("MyPrefix"), Assembly.GetExecutingAssembly()))
{
OnContextCreated();
}
}
This partial class has the same name as the partial class generated by the Entity Framework. You should remove the generated constructors and base class specification from that one or your code will not compile. Note that every time you update the model with the designer it will regenerate the constructors etc. so you have to remove them every time.
In this example I’m using the TablePrefixModelAdapter which will prefix all my tables with my specified prefix, in this case “MyPrefix”. Consuming this context is done just like a normal ObjectContext. You also need to specify where the mappings that need to be altered are located, in this sample I’m using a single console application so they are contained in the executing assembly.
using(var context = new AdventureWorksEntities())
{
var products = context.Products;
products.ToList().ForEach(x => Console.Write(x.Name));
} |
using(var context = new AdventureWorksEntities())
{
var products = context.Products;
products.ToList().ForEach(x => Console.Write(x.Name));
}
And this generates the following SQL:
SELECT
1 AS [C1],
[Extent1].[ProductID] AS [ProductID],
[Extent1].[Name] AS [Name],
[Extent1].[ProductNumber] AS [ProductNumber],
...
FROM [Production].[MyPrefixProduct] AS [Extent1] |
SELECT
1 AS [C1],
[Extent1].[ProductID] AS [ProductID],
[Extent1].[Name] AS [Name],
[Extent1].[ProductNumber] AS [ProductNumber],
...
FROM [Production].[MyPrefixProduct] AS [Extent1]
So we’re all set to support multi tenancy? Not quite. The code as available in the CodePlex project stores the updated mappings in a static variable for performance reasons, this is great if you’re developing against a development database and your code will run against a production database with different naming or schema.
For a multi tenant application we need a different model for each of our customers so we need to make another change to the code as available in the CodePlex project. If you don’t mind taking the performance hit to rewrite the mapping every single time an object context is created you can just open the ConnectionAdapter class and change the static variables which hold the model information to instance variables.
And optimized version would store all the mappings per customer so you only rewrite the mappings once a new customer hits the context, and from that point store them in i.e. a dictionary with key the customerID and value the updated mappings.
I’ve used Entity Framework 3.5 SP1 and Visual Studio 2008 in this post.