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?
J'ai trouvé plusieurs réponses à cette question.
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.
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)
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 à: