web-dev-qa-db-fra.com

Comment exécuter un script SQL de migration à l'aide d'Entity Framework Core

J'ai rencontré un problème où je ne peux pas atteindre le script SQL pour appliquer la migration. Voici mon code de migration:

 public partial class AddSomethingMigration : Migration
{
    private const string MIGRATION_SQL_SCRIPT_FILE_NAME = @"Migrations\Scripts\20170710123314_AddSomethingMigration.sql";

    protected override void Up(MigrationBuilder migrationBuilder)
    {
        string sql = Path.Combine(Directory.GetParent(Directory.GetCurrentDirectory()).FullName, MIGRATION_SQL_SCRIPT_FILE_NAME));
        migrationBuilder.Sql(File.ReadAllText(sql));
    }
}

Ainsi, lorsque j'utilise la console du gestionnaire de packages sur la machine locale, tout fonctionne bien. Mais lorsque je déploie dans l'environnement, j'obtiens la différence avec le fichier.

Puis-je exécuter automatiquement mes scripts SQL statiques via la migration EF ou dois-je coller la requête SQL en ligne dans le code?

11
shkapo

J'ai trouvé plusieurs réponses à cette question.

  1. Ajoutez des scripts en tant que ressources de projet et utilisez-les comme:

        string sql = Resources._20170630085940_AddMigration;
        migrationBuilder.Sql(sql);
    

Cette option n'est pas très bonne, car le .sql sera intégré à l'Assemblée.

  1. Si vous utilisez des projets Net Core avec la structure .csproj, vous pouvez ajouter le groupe d'éléments au xml:

    <ItemGroup> <Content Include="Migrations\**\*.sql" CopyToPublishDirectory="PreserveNewest" /><!-- CopyToPublishDirectory = { Always, PreserveNewest, Never } --></ItemGroup>
    

Et puis spécifiez le chemin d'accès au fichier comme:

Path.Combine(AppContext.BaseDirectory, relativePath)
14
shkapo

Il s'agit d'une mise à niveau de la méthode qui utilise EmbeddedResource . L'idée principale est d'utiliser une classe abstraite et un fichier sql portant le même nom que la migration.

public abstract class SqlMigration : Migration
{
    protected sealed override void Up(MigrationBuilder migrationBuilder)
    {
        var Assembly = Assembly.GetExecutingAssembly();
        var type = GetType();
        var regex = new Regex($@"{Regex.Escape(type.Namespace)}\.\d{{14}}_{Regex.Escape(type.Name)}\.sql");

        var resourceName = Assembly.GetManifestResourceNames().FirstOrDefault(x => regex.IsMatch(x));
        using var stream = Assembly.GetManifestResourceStream(resourceName);
        using var reader = new StreamReader(stream);
        var sqlResult = reader.ReadToEnd();
        migrationBuilder.Sql(sqlResult);
    }
}

Il utilise simplement le nom et l'espace de noms de type réel pour l'expression régulière. La classe hérite ressemblera à:

public partial class RunSqlScript : SqlMigration
{
    protected override void Down(MigrationBuilder migrationBuilder)
    {
        // Down code here
    }
}

Le projet ressemblera à:

enter image description here .

0
4lexKislitsyn