I know this question is a bit old, but I came across it in my research and came up with a solution that may benefit others, and have discussed it privately with @ppumkin.
The schema name can be passed as a string to the ToTable() method, so essentially using a member of the containing class instead of a hard-coded value allows you to dynamically specify the schema name upon context creation.
This is a dumbed down version of what I have:
public class FooDbContext : DbContext
{
public string SchemaName { get; set; }
static FooDbContext()
{
Database.SetInitializer<FooDbContext>(null);
}
public FooDbContext(string schemaName)
: base("name=connString1")
{
this.SchemaName = schemaName;
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new City_Map(this.SchemaName));
modelBuilder.Configurations.Add(new Customer_Map(this.SchemaName));
modelBuilder.Configurations.Add(new CustomerSecurity_Map(this.SchemaName));
base.OnModelCreating(modelBuilder);
}
public DbSet<Customer> Customers { get; set; }
public DbSet<City> Cities { get; set; }
}
And the mapping abstract class:
public abstract class SchemaNameEntityTypeConfiguration<TEntityType> : EntityTypeConfiguration<TEntityType> where TEntityType : class
{
public string SchemaName { get; set; }
public SchemaNameEntityTypeConfiguration(string schemaName)
: base()
{
this.SchemaName = schemaName;
}
public new void ToTable(string tableName)
{
base.ToTable(tableName, SchemaName);
}
}
Implementation:
public class City_Map : SchemaNameEntityTypeConfiguration<City>
{
public City_Map(string schemaName)
: base(schemaName)
{
ToTable("City");
HasKey(t => t.Code);
Property(t => t.Code)
.HasColumnType("integer")
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
Property(t => t.CityName)
.HasColumnName("City")
.HasMaxLength(50);
Property(t => t.State)
.HasMaxLength(2);
}
}
The key thing to note here is the ToTable()
method in SchemaNameEntityConfiguration
. It overrides the superclass' method so when the implementations call ToTable(tableName)
it supplies the schema name as well.
*Important note: EntityTypeConfiguration.ToTable()
is non-virtual, and the abstract SchemaNameEntityTypeConfiguration
hides that method with its own and thus won't be called virtually if the _Map
object is type as EntityTypeConfiguration
.
It was one concern of mine but there's an easy (and only slightly annoying) work around: instead of implementing a base class that supplies it automatically, just ensure in the _Map
classes you pass the schemaName
to ToTable()
.
Usage:
using (FooDbContext context = new FooDbContext("theSchemaName"))
{
foreach (
var customer in context.Customers
.Include(c => c.City)
.Where(c => c.CustomerName.StartsWith("AA"))
.OrderBy(c => c.CustomerCode)
)
{
Console.WriteLine(string.Format(
"{0:20}: {1} - {2}, {3}",
customer.CustomerCode,
customer.CustomerName,
customer.City.CityName,
customer.City.State));
}
}
Disclaimer: I haven't tested using multiple contexes within the same program. It shouldn't have an issue, but if the DbContext caches the model at a static class level (rather than at the instance-level), it could be a problem. That may be resolved by creating separate subclasses of the context though, each specifying a different schema name.