Я знаю, что этот вопрос немного стар, но я наткнулся на него в своем исследовании и нашел решение, которое может принести пользу другим, и обсудил его в частном порядке с @ ppumkin.
Имя схемы может быть передано в виде строки в метод ToTable (), поэтому, по существу, использование члена содержащего класса вместо жестко заданного значения позволяет динамически указывать имя схемы при создании контекста.
Это тупая версия того, что у меня есть:
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; }
}
И отображение абстрактного класса:
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);
}
}
Реализация:
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);
}
}
Ключевым моментом, на который следует обратить внимание, является метод ToTable()
в SchemaNameEntityConfiguration
. Он переопределяет метод суперкласса, поэтому, когда реализации вызывают ToTable(tableName)
, он также предоставляет имя схемы.
* Важное примечание: EntityTypeConfiguration.ToTable()
не является виртуальным, и абстрактный SchemaNameEntityTypeConfiguration
скрывает этот метод своим собственным и, следовательно, не будет вызываться виртуально, если объект _Map
имеет тип EntityTypeConfiguration
.
Это была моя проблема, но есть простой (и немного раздражающий) обходной путь: вместо реализации базового класса, который предоставляет его автоматически, просто убедитесь, что в _Map
классах вы передаете schemaName
в ToTable()
.
Использование:
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));
}
}
Отказ от ответственности: я не тестировал использование нескольких контекстов в одной программе. Это не должно иметь проблемы, но если DbContext кэширует модель на статическом уровне класса (а не на уровне экземпляра), это может быть проблемой. Это может быть решено путем создания отдельных подклассов контекста, каждый из которых указывает свое имя схемы.