2011-08-25 19 views
14

Estoy intentando conectarme a una base de datos de SQL Server 2008 en un entorno de alojamiento compartido desde C# desde ASP.NET MVC 3 aplicación que se conecta a través de EF (código primero).Especifique un nombre de usuario de SQL que no sea dbo en Code First Entity Framework (C# ASP.NET MVC 3)

Mi problema es que la generada SELECT afirmación se ve así:

SELECT ... FROM [dbo].[TableName] 

que arroja el error Invalid object name, pero funciona bien cuando lo haga:

SELECT ... FROM [mySQLUserName].[TableName] 

¿Cómo se especifica un nombre de usuario de otro que dbo (por ejemplo, mySQLUserName)?


EDIT:

Los artículos cercano que he encontrado que son relevantes para este problema son:

con énfasis específico en estas cond artículo, sin embargo, no especifica cómo establecer un nombre de usuario que no sea dbo

Respuesta

13

Puede especificar el esquema utilizando una propiedad en el TableAttribute que decora sus clases de entidad.

[Table("TableName", Schema = "mySQLUserName")] 
+0

¡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 –

+0

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. –

+5

¿Hay alguna manera de establecer esto globalmente? EF utiliza DBO por deafult wihtout nos specyfing ella .. tan molesto cambiar todas mis clases – ppumkin

3

Usted puede adornar su clase con el TableAttribute y especificar el esquema, o usted podría intentar lo que este post describe.

+0

¡El decorador funciona maravillosamente! –

7

No dice qué versión de EF está utilizando. Si está utilizando código de Primera (4.1) se puede especificar el esquema de un atributo de tabla:

[Table("Users", Schema = "myschema")] 
public class User { .. } 

Puede utilizar el artículo de Scott (el segundo) como base, pero añadir un parámetro adicional. es decir .:

modelBuilder.Entity<YourType>().ToTable("TableName", "SchemaName"); 
+0

Gracias! No sabía que el método 'ToTable' estaba sobrecargado para permitir la especificación de un nombre de esquema. ¡Muy útil! –

+0

Esto arruinará la pluralización. – ANeves

4

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.

+1

¡Gracias! y waht una respuesta espectacular que es +1 + cerveza – ppumkin

7

Con EF6, ahora se puede hacer esto.

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     modelBuilder.HasDefaultSchema("logs"); //set default schema 
     modelBuilder.Configurations.Add(new LogMap()); 
     ... 
    } 
Cuestiones relacionadas