Una delle novità introdotte con EF6 è la possibilità di gestire molteplici modelli per singola istanza di database, che non vuol dire usare lo stesso contesto piu’ volte nello stesso database, ma poter utilizzare Entity Framework Migrations e relativa Migration History Table per gestire la migrazione di due o piu’ modelli per singolo database fisico. Specifichiamo questa feature come Multi-Tenant Migrations.
Come esempio, supponiamo di avere due classi Bus e Car facenti parte dello stesso Domain di una nostra applicazione, ma interessate da due DbContext diversi, rispettivamente BusContext e CarContext, come da Class Diagram seguente:
Provando ad abilitare EF Migrations per il progetto corrente, essendo presenti due DbContext, il “Package Manager Console” risponderebbe restituendo l’errore seguente:
Vediamo come utilizzare Multi-Tenant Migrations: iniziamo ad utilizzare la prima delle novità di EF6 (migrations), l’opzione “-MigrationDirectory” che ci permette di specificare, insieme all’opzione “-ContextTypeName” che rispettivamente indicano dove far risiedere i piani di migrazione e quale DbContext considerare. Il comando completo da utilizzare diventa quindi:
PM>Enable-Migrations -MigrationsDirectory BusDbContextMigration -ContextTypeName MultiTenantMigration.BusContext
Questa volta tutto fila liscio, ottenendo un messaggio di questo tipo:
Il “Solution Explorer” dovrebbe apparire simile alla figura seguente:
Visualizziamo il codice della classe Configuration.cs e modifichiamolo opportunatamente impostando la proprietà ContextKey che altro non è una nuova proprietà di configurazione per EF6 Migrations che aggiunge nella “_MigrationHistory Table” una nuova colonna che rende possibile la funzionalità “Multi-Tenant”:
public Configuration()
{
ContextKey = "BusContextKey";
AutomaticMigrationsEnabled = false;
MigrationsDirectory = @"BusDbContextMigration";
}
Come prima, eseguiamo le operazioni precedenti per abilitare la migrazione anche per il DbContext “CarContext” ottenendo un “Solution Explorer” simile al seguente:
E per Configuration.cs:
public Configuration()
{
ContextKey = "CarContext";
AutomaticMigrationsEnabled = false;
MigrationsDirectory = @"CarDbContextMigration";
}
Aggiungiamo i corrispettivi piani di migrazione:
PM> Add-Migration CarDbMigration -ConfigurationTypeName MultiTenantMigration.CarDbContextMigration.Configuration
Scaffolding migration 'CarDbMigration'
PM> Add-Migration BusDbMigration -ConfigurationTypeName MultiTenantMigration.BusDbContextMigration.Configuration
Scaffolding migration 'BusDbMigration'
Procediamo con l’aggiornamento del database (ricordiamo essere lo stesso per i due DbContext). Procediamo con CarDbContext:
PM> Update-Database -ConfigurationTypeName MultiTenantMigration.CarDbContextMigration.Configuration
Specify the '-Verbose' flag to view the SQL statements being applied to the target database.
Applying explicit migrations: [201308141834283_CarDbMigration].
Applying explicit migration: 201308141834283_CarDbMigration.
Running Seed method.
Il messaggio indica che l’aggiornamento è stato completato con successo. Passiamo ora a BusDbContext:
PM> Update-Database -ConfigurationTypeName MultiTenantMigration.BusDbContextMigration.Configuration
Specify the '-Verbose' flag to view the SQL statements being applied to the target database.
Applying explicit migrations: [201308141835410_BusDbMigration].
Applying explicit migration: 201308141835410_BusDbMigration.
Running Seed method.
A livello database:
In dettaglio, la tabella “MigrationHistory” è popolata con le seguenti righe (da notare la colonna ContextKey):
A questo punto, tutte le successive modifiche al modello, ed i relativi piani di migrazione dovrebbero essere applicati con successo.