EF Code First Migrations zur Bereitstellung älterer Versionen

Ich verwende TFS Release Management für die kontinuierliche Integration und Bereitstellung.

Ich verwende migrate.exe, um die Datenbankmigration während der Bereitstellung durchzuführen. Dies funktioniert hervorragend, wenn Sie von einer älteren Version zu einer neueren Version wechseln. Wenn Sie jedoch eine ältere Version der Anwendung bereitstellen möchten, wird diese schlammiger.

Grundsätzlich muss die Assembly, die Ihre Migrationen für einen Kontext enthält, wissen, wie von Version 3 auf Version 2 übergegangen wird. Normalerweise verwenden Sie die Assemblys, die Sie bereitstellen möchten, als Quelle für Ihre Migrationen. In diesem Fall müssen Sie dies jedoch tun Verwenden Sie die bereits bereitgestellten Assemblys, da sie die einzigen sind, die wissen, wie man von Version 3 auf Version 2 herunterfährt. (Version 2 hat keine Ahnung, dass v3 überhaupt existiert.)

Mein aktueller Plan ist es, die beiden Assemblys während der Bereitstellung zu vergleichen. Wenn die Assembly im Installationsverzeichnis "neuere" Migrationen als die im Deployment Director enthält, muss zuerst die "neueste" verfügbare Migration in der Assembly im Deployment-Verzeichnis abgerufen und dann ausgeführt werden:

migrate.exe AssemblyInInstallationDir /targetMigration NewestFromAssemblyInDeploymentDir

Wo wie in einem "normalen" Bereitstellungsszenario, in dem Sie auf eine neuere Version aktualisieren, können Sie einfach Folgendes tun:

migrate.exe AssemblyInDeploymentDir

Ist das ein legitimer Ansatz? Ich habe mich noch nicht mit der Verwendung von EF-Bibliotheken befasst, um zu bewerten, welche Migrationen in jeder Assembly verfügbar sind. Es besteht auch die Herausforderung darin, dass jede dieser Baugruppen "dieselbe", nur unterschiedliche Versionen aufweist. Ich muss sie wahrscheinlich in separate App-Domänen laden und dann die domänenübergreifende Kommunikation verwenden, um die benötigten Informationen zu erhalten.

BEARBEITEN

Ich habe eine Proof-of-Concept-App erstellt, mit der ich die verfügbaren Migrationen zu zwei verschiedenen Versionen derselben Assembly auflisten kann. Dies war für den gesamten Prozess von entscheidender Bedeutung, daher fand ich, dass es sich lohnt, dies zu dokumentieren.

Die App verwendet Reflection, um die einzelnen Assemblys zu laden, und verwendet dann die DbMigrator-Klasse aus System.Data.Entity.Migrations, um die Migrations-Metadaten aufzulisten. Den Namen der Migrationen werden Zeitstempelinformationen vorangestellt, sodass ich sie bestellen und sehen kann, welche Assembly den "neueren" Satz von Migrationen enthält.

static void Main(string[] args)
{
    const string dllName = "Test.Data.dll";
    var assemblyCurrent = Assembly.LoadFile(Path.Combine(System.Environment.CurrentDirectory, string.Format("Current\\{0}", dllName)));
    var assemblyTarget = Assembly.LoadFile(Path.Combine(System.Environment.CurrentDirectory, string.Format("Target\\{0}", dllName)));

    Console.WriteLine("Curent Version: " + assemblyCurrent.FullName);
    Console.WriteLine("Target Version: " + assemblyTarget.FullName);

    const string contextName = "Test.Data.TestContext";
    const string migrationsNamespace = "Test.Data.Migrations";
    var currentContext = assemblyCurrent.CreateInstance(contextName);
    var targetContext = assemblyTarget.CreateInstance(contextName);

    var currentContextConfig = new DbMigrationsConfiguration
    {
        MigrationsAssembly = assemblyCurrent,
        ContextType = currentContext.GetType(),
        MigrationsNamespace = migrationsNamespace
    };

    var targetContextConfig = new DbMigrationsConfiguration
    {
        MigrationsAssembly = assemblyTarget,
        ContextType = targetContext.GetType(),
        MigrationsNamespace = migrationsNamespace
    };

    var migrator = new DbMigrator(currentContextConfig);
    var localMigrations = migrator.GetLocalMigrations(); //all migrations

    Console.WriteLine("Current Context Migrations:");
    foreach (var m in localMigrations)
    {
        Console.WriteLine("\t{0}", m);
    }

    migrator = new DbMigrator(targetContextConfig);
    localMigrations = migrator.GetLocalMigrations(); //all migrations

    Console.WriteLine("Target Context Migrations:");
    foreach (var m in localMigrations)
    {
        Console.WriteLine("\t{0}", m);
    }

    Console.ReadKey();
}

}

Die Ausgabe der Anwendung sieht folgendermaßen aus:

Curent Version: Test.Data, Version=1.3.0.0, Culture=neutral, PublicKeyToken=null
Target Version: Test.Data, Version=1.2.0.0, Culture=neutral, PublicKeyToken=null

Current Context Migrations:
    201403171700348_InitalCreate
    201403171701519_AddedAddresInfoToCustomer
    201403171718277_RemovedStateEntity
    201403171754275_MoveAddressInformationIntoContactInfo
    201403181559219_NotSureWhatIChanged
    201403181731525_AddedRowVersionToDomainObjectBase
Target Context Migrations:
    201403171700348_InitalCreate
    201403171701519_AddedAddresInfoToCustomer
    201403171718277_RemovedStateEntity

Antworten auf die Frage(2)

Ihre Antwort auf die Frage