2011-08-25 7 views
14

Sto provando a connettermi a un database di SQL Server 2008 in un ambiente di hosting condiviso da C# all'interno di un ASP.NET MVC 3 applicazione che si collega tramite EF (prima il codice).Specificare un nome utente SQL diverso da dbo in Code First Entity Framework (C# ASP.NET MVC 3)

mio problema è che il generato SELECT dichiarazione si presenta in questo modo:

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

che genera l'errore Invalid object name, ma funziona bene quando lo faccio:

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

Come faccio a specificare un nome utente altra di dbo (ad es. mySQLUserName)?


EDIT:

Gli articoli più vicini ho trovato che sono rilevanti per questo problema sono:

con particolare enfasi sulla queste cond articolo, tuttavia non specifica come impostare un nome utente diverso da dbo

risposta

13

È possibile specificare lo schema utilizzando una proprietà su TableAttribute che decora le classi di entità.

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

Signore, sei un genio! Si sa, questa è in realtà una risposta molto migliore di quella fornita per questa domanda: http://stackoverflow.com/questions/6399443/entityframework-using-wrong-tablename –

+0

La soluzione 'OnModelCreating' /' ToTable' è utile per scenari di mapping più avanzati, ma poiché si conosce il nome dello schema in fase di compilazione, l'opzione semplice dovrebbe funzionare correttamente. –

+5

C'è un modo per impostarlo globalmente? EF usa dbo by deafult senza che lo specifichiamo .. così fastidioso cambiando tutte le mie classi – ppumkin

3

è possibile decorare la vostra classe con l'TableAttribute e specificare lo schema, o si potrebbe provare cosa questo post descrive.

+0

Il decoratore funziona magnificamente! –

7

Non si dice quale versione di EF si sta utilizzando. Se stai usando codice First (4.1) è possibile specificare lo schema su un attributo tavolo:

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

È possibile utilizzare l'articolo di Scott (il secondo) come base, ma si aggiunge un parametro aggiuntivo. vale a dire .:

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

Grazie! Non ero a conoscenza del fatto che il metodo 'ToTable' fosse sovraccarico per consentire la specifica di un nome di schema. Molto utile! –

+0

Questo rovinerà la pluralizzazione. – ANeves

4

so che questa domanda è un po 'vecchio, ma mi sono imbattuto nella mia ricerca e si avvicinò con una soluzione che può beneficiare gli altri, e hanno discusso privatamente con @ppumkin.

Il nome dello schema può essere passato come una stringa al metodo ToTable(), quindi essenzialmente utilizzando un membro della classe contenitore anziché un valore codificato consente di specificare dinamicamente il nome dello schema al momento della creazione del contesto.

Questa è una versione dumbed giù di ciò che ho:

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; } 

} 

E la mappatura classe astratta:

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); 
    } 
} 

Implementazione:

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 cosa fondamentale da notare qui è il metodo ToTable() in SchemaNameEntityConfiguration. Sostituisce il metodo della superclasse, quindi quando le implementazioni chiamano ToTable(tableName), fornisce anche il nome dello schema.

Importante: EntityTypeConfiguration.ToTable() è non virtuale, e l'astratto SchemaNameEntityTypeConfiguration nasconde tale metodo con una propria e quindi non si chiamerà praticamente se l'oggetto è _Map tipo EntityTypeConfiguration.

E 'stata una mia preoccupazione, ma c'è un facile (e solo un po' fastidioso) aggirare: invece di attuare una classe di base che fornisce automaticamente, basta garantire nei _Map classi si passa il schemaName-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: non ho ancora testato l'utilizzo di più contexes all'interno dello stesso programma. Non dovrebbe avere un problema, ma se DbContext memorizza nella cache il modello a livello di classe statico (piuttosto che a livello di istanza), potrebbe essere un problema. Ciò può essere risolto creando sottoclassi separate del contesto, ognuna specificando un nome di schema diverso.

+1

Grazie! e con una risposta spettacolare che è +1 + birra – ppumkin

7

Con EF6, ora è possibile farlo.

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