Sé que esta pregunta es un poco viejo, pero me encontré en mi investigación y se le ocurrió una solución que puede beneficiar a otros, y se han discutido en privado con @ppumkin.
El nombre del esquema se puede pasar como una cadena al método ToTable(), por lo que usar un miembro de la clase contenedora en lugar de un valor codificado le permite especificar dinámicamente el nombre del esquema al crear el contexto.
Ésta es una versión callados de lo que tengo:
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; }
}
Y la clase abstracta mapeo:
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);
}
}
Implementación:
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);
}
}
La clave a destacar aquí es el método ToTable()
en SchemaNameEntityConfiguration
. Anula el método de la superclase, por lo que cuando las implementaciones llaman al ToTable(tableName)
, también proporciona el nombre del esquema.
* Nota importante: EntityTypeConfiguration.ToTable()
es no virtual, y el resumen SchemaNameEntityTypeConfiguration
esconde ese método con su propia y por lo tanto no serán llamados virtualmente si el objeto es _Map
tipo que EntityTypeConfiguration
.
Fue una preocupación mía pero no hay una forma fácil (y sólo un poco molesto) evitar: en lugar de implementar una clase base que lo suministra de forma automática, simplemente garantizar en las clases _Map
que pase el schemaName
-ToTable()
.
Uso:
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));
}
}
de responsabilidad: No he probado el uso de múltiples contexes dentro del mismo programa. No debería tener un problema, pero si el DbContext guarda en caché el modelo en un nivel de clase estático (en lugar de en el nivel de instancia), podría ser un problema. Sin embargo, esto puede resolverse creando subclases separadas del contexto, cada una especificando un nombre de esquema diferente.
¡Usted señor, es un genio! Ya sabes, esta es en realidad una respuesta mucho mejor que la proporcionada para esta pregunta: http://stackoverflow.com/questions/6399443/entityframework-using-wrong-tablename –
La solución 'OnModelCreating' /' ToTable' es bueno para los escenarios de mapeo más avanzados, pero ya que conoce el nombre del esquema en tiempo de compilación, la opción simple debería funcionar bien. –
¿Hay alguna manera de establecer esto globalmente? EF utiliza DBO por deafult wihtout nos specyfing ella .. tan molesto cambiar todas mis clases – ppumkin