2015-09-08 16 views
14

Ho problemi nell'utilizzo delle migrazioni di Entity Framework indirizzate ai database Oracle poiché il nome dello schema è incluso nel codice di migrazione e per Oracle, il nome dello schema è anche nome utente. Il mio obiettivo è quello di avere Code First Migrations indipendenti dallo schema (per poter avere una serie di migrazioni per gli ambienti di test e produzione).Codice schema entità indipendente dallo schema Prime migrazioni

Ho già provato questo approccio (utilizzando Entity Framework 6.1.3):

1) Non ho nome dello schema in Web.config:

<add key="SchemaName" value="IPR_TEST" /> 

2) Il mio DbContext prende nome dello schema come parametro del costruttore:

public EdistributionDbContext(string schemaName) 
    : base("EdistributionConnection") 
{ 
    _schemaName = schemaName; 
} 

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    modelBuilder.HasDefaultSchema(_schemaName); 
} 

3) ho dovuto implementare IDbContextFactory per l'entità migrazioni Framework per essere in grado di creare il mio DbContext che non ha costruttore senza parametri:

public class MigrationsContextFactory : IDbContextFactory<EdistributionDbContext> 
{ 
    public EdistributionDbContext Create() 
    { 
     return new EdistributionDbContext(GetSchemaName()); 
    } 
} 

4) Ho anche configurato migrazione Storia Tavolo da collocare entro corretto schema:

public class EdistributionDbConfiguration : DbConfiguration 
{ 
    public EdistributionDbConfiguration() 
    { 
     SetDefaultHistoryContext((connection, defaultSchema) 
      => new HistoryContext(connection, GetSchemaName())); 
    } 
} 

5) ho modificato il codice generato per le migrazioni per sostituire nome dello schema hardcoded. Per esempio. Ho sostituito CreateTable("IPR_TEST.Users") con CreateTable($"{_schema}.Users"). (Il campo _schema viene impostato in base al valore in Web.config).

6) Uso l'inizializzatore del database MigrateDatabaseToLatestVersion<EdistributionDbContext, MigrationsConfiguration>().

Avere tutto questo set up, ho ancora problemi quando passo a diverso schema (ad esempio tramite web.config trasformazione.) - viene generata un'eccezione che mi diceva che database non corrisponde il mio modello e AutomaticMigrations sono disabilitate (che è desiderato). Quando provo ad eseguire add-migration una nuova migrazione viene generato in cui tutti gli oggetti deve essere spostato in diversi schemi (es. MoveTable(name: "IPR_TEST.DistSetGroups", newSchema: "IPR");, che non è sicuramente desidera

Per me sembra che il nome dello schema è hard-wired da qualche parte in stringa del modello -hash in classe migrazione (ad es 201509080802305_InitialCreate.resx.), vale a dire:

<data name="Target" xml:space="preserve"> 
    <value>H4sIAAAAAAAEAO09227jO... </value> 
</data> 

e c'è un modo come dire Codice prime migrazioni di ignorare nome dello schema

+0

Sono sicuro di averlo provato, ma con il server SQL, se semplicemente non si specifica lo schema nei collegamenti del modello, si utilizza solo lo schema predefinito per l'utente. –

+2

Grazie @Ben, il tuo commento potrebbe portare a una soluzione del mio problema. Quando ometti 'modelBuilder.HasDefaultSchema (" SCHEMA_NAME ");' Entity Framework imposta "dbo" come schema predefinito. Comunque, ora ho provato 'modelBuilder.HasDefaultSchema (string.Empty);' e sembra che ora lo schema predefinito per l'utente sia (correttamente) usato. Purtroppo, 'Oracle.ManagedDataAccess.EntityFramework.OracleMigrationSqlGenerator' che viene utilizzato per generare SQL per le migrazioni ha problemi con' string.Empty'-schema-name e genera eccezioni durante la generazione di SQL di migrazione ... Ma questo è un altro problema ... –

+0

Ciao Jan Palas, hai trovato qualche soluzione su questo problema? Ho esattamente lo stesso problema, utilizzo EF Migration con Oracle e quando cambio lo schema, tutti gli script di migrazione contengono MoveTable ... – toregua

risposta

1

È possibile creare un derivato DbContext e "override? "modelBuilder.HasDefaultSchema(...) in OnModelCreating:

public class TestDbContext : ProductionDbContext 
{ 
    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     base.OnModelCreating(modelBuilder); 

     modelBuilder.HasDefaultSchema("TestSchema"); 
    } 
} 

Quindi è possibile creare migrazioni per entrambi i contesti. Vedere this question su come creare due migrazioni in un progetto.

Lo svantaggio di questo approccio è che è necessario mantenere due migrazioni separate. Ma ti dà l'opportunità di regolare la configurazione del tuo TestDbContext.

1

mi trovai di fronte al medesimo problema e grazie al vostro aproach ho finalmente trovato una soluzione che sembra funzionare abbastanza bene:

1) Non ho il nome dello schema in Web.impostazioni di configurazione app:

<add key="Schema" value="TEST" /> 

2) Ho un contesto di storia:

public class HistoryDbContext : HistoryContext 
{ 
    internal static readonly string SCHEMA; 

    static HistoryDbContext() 
    { 
     SCHEMA = ConfigurationManager.AppSettings["Schema"]; 
    } 

    public HistoryDbContext(DbConnection dbConnection, string defaultSchema) 
      : base(dbConnection, defaultSchema) 
    { } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     base.OnModelCreating(modelBuilder); 
     modelBuilder.HasDefaultSchema(SCHEMA); 
    } 
} 

3) Ho un DB di configurazione che fanno riferimento a mio contesto storia db:

public class MyDbConfiguration : DbConfiguration 
{ 
    public MyDbConfiguration() 
    { 
     SetDefaultHistoryContext((connection, defaultSchema) => new HistoryDbContext(connection, defaultSchema)); 
    } 
} 

4) E questo è il mio contesto db:

public partial class MyDbContext : DbContext 
{ 
    public MyDbContext() 
     : base("name=MyOracleDbContext") 
    { } 

    public static void Initialize() 
    { 
     DbConfiguration.SetConfiguration(new MyDbConfiguration()); 
     Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyDbContext, Migrations.Configuration>()); 
    } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     modelBuilder.HasDefaultSchema(string.Empty); 
    } 
} 

5) Infine chiamo il metodo di inizializzazione dal global.asax

protected void Application_Start() 
{ 
    MyDbContext.Initialize(); 
} 

La chiave è quello di impostare lo schema predefinito del contesto db per String.Empty e lo schema del contesto della storia a quella corretta. Quindi quando si creano le migrazioni sono indipendenti dallo schema: la variabile DefaultSchema del resx della migrazione sarà vuota. Tuttavia, lo schema del contesto di database della cronologia è ancora corretto per consentire il passaggio dei controlli delle migrazioni.

Sto usando i seguenti pacchetti nugets:

<package id="EntityFramework" version="6.2.0" targetFramework="net452" /> 
<package id="Oracle.ManagedDataAccess" version="12.2.1100" targetFramework="net452" /> 
<package id="Oracle.ManagedDataAccess.EntityFramework" version="12.2.1100" targetFramework="net452" /> 

è quindi possibile utilizzare le migrazioni Oracle con successo su diversi database.

+0

Confermato di funzionare.L'impostazione del nome schema solo su HistoryDbContext è davvero la differenza che fa la differenza e rende tutto a posto. Vorrei sottolineare il fatto che se si utilizzano configurazioni fluenti/annotazioni di dati e si desidera utilizzare questo approccio, è necessario * assicurarsi che non si imposti il ​​nome dello schema in nessun punto delle proprie annotazioni/annotazioni di dati fluenti (basta lasciare il nome dello schema alla stringa vuota). – xDisruptor