[英]How to run migration SQL script using Entity Framework Core
I faced with an issue, where I can't reach the SQL script to apply the migration.我遇到了一个问题,我无法访问 SQL 脚本来应用迁移。 Here is my migration code:这是我的迁移代码:
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));
}
}
So when I use the Package Manager Console on the local machine all works fine.因此,当我在本地机器上使用 Package 管理器控制台时,一切正常。 But when I deploy to the environment I get the discrepancy to the file.但是当我部署到环境时,我得到了文件的差异。
Can I run my static SQL scripts via EF migration automatically at all, or I should paste the SQL query inline in code?我可以通过 EF 迁移自动运行我的 static SQL 脚本,还是应该将 SQL 查询内联粘贴到代码中?
I faced with an issue, where I can't reach the SQL script to apply the migration.我遇到了一个问题,我无法访问 SQL 脚本来应用迁移。 Here is my migration code:这是我的迁移代码:
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));
}
}
So when I use the Package Manager Console on the local machine all works fine.所以当我在本地机器上使用包管理器控制台时一切正常。 But when I deploy to the environment I get the discrepancy to the file.但是当我部署到环境时,我得到了文件的差异。
Can I run my static SQL scripts via EF migration automatically at all, or I should paste the SQL query inline in code?我可以通过 EF 迁移自动运行我的静态 SQL 脚本,还是应该将 SQL 查询内联粘贴到代码中?
I faced with an issue, where I can't reach the SQL script to apply the migration.我遇到了一个问题,我无法访问 SQL 脚本来应用迁移。 Here is my migration code:这是我的迁移代码:
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));
}
}
So when I use the Package Manager Console on the local machine all works fine.所以当我在本地机器上使用包管理器控制台时一切正常。 But when I deploy to the environment I get the discrepancy to the file.但是当我部署到环境时,我得到了文件的差异。
Can I run my static SQL scripts via EF migration automatically at all, or I should paste the SQL query inline in code?我可以通过 EF 迁移自动运行我的静态 SQL 脚本,还是应该将 SQL 查询内联粘贴到代码中?
I faced with an issue, where I can't reach the SQL script to apply the migration.我遇到了一个问题,我无法访问 SQL 脚本来应用迁移。 Here is my migration code:这是我的迁移代码:
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));
}
}
So when I use the Package Manager Console on the local machine all works fine.所以当我在本地机器上使用包管理器控制台时一切正常。 But when I deploy to the environment I get the discrepancy to the file.但是当我部署到环境时,我得到了文件的差异。
Can I run my static SQL scripts via EF migration automatically at all, or I should paste the SQL query inline in code?我可以通过 EF 迁移自动运行我的静态 SQL 脚本,还是应该将 SQL 查询内联粘贴到代码中?
I created an extensions method based on 4lexKislitsyn 's answer.我根据4lexKislitsyn的回答创建了一个扩展方法。 This assumes that your files end with a .sql
extension and that it's an embeded resource in whatever project your running the migrations from.这假设您的文件以.sql
扩展名结尾,并且它是您运行迁移的任何项目中的嵌入资源。 You could of course move the .sql
part to the Up
of your migration but this seemed cleaner to me.您当然可以将.sql
部分移动到迁移的Up
部分,但这对我来说似乎更清晰。
public static class MigrationExtensions
{
public static void RunSqlScript(this MigrationBuilder migrationBuilder, string script)
{
var assembly = Assembly.GetExecutingAssembly();
var resourceName = assembly.GetManifestResourceNames().FirstOrDefault(x => x.EndsWith($"{script}.sql"));
using var stream = assembly.GetManifestResourceStream(resourceName);
using var reader = new StreamReader(stream);
var sqlResult = reader.ReadToEnd();
migrationBuilder.Sql(sqlResult);
}
}
Used as用作
public partial class AddViews : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.RunSqlScript("nameOfMyFile");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
}
}
I've found that evaluating the sql file name from the provided MigrationAttribute the best approach.我发现从提供的 MigrationAttribute 评估 sql 文件名是最好的方法。
public class EmbeddedSqlFileMigration : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
var assembly = Assembly.GetExecutingAssembly();
var type = GetType();
var migrationAttribute = type.GetCustomAttribute<MigrationAttribute>();
if (migrationAttribute == null)
throw new InvalidOperationException("A migration requires a MigrationAttribute.");
var sqlResourceFilename = $"{type.Namespace}.{migrationAttribute.Id}.sql";
var resourceName = assembly.GetManifestResourceNames().FirstOrDefault(r => r == sqlResourceFilename);
if (resourceName == null)
{
throw new FileNotFoundException(
$"Embedded resource '{sqlResourceFilename}' was not found in assembly '{assembly.FullName}'.");
}
using var stream = assembly.GetManifestResourceStream(resourceName);
if (stream == null)
{
throw new InvalidOperationException(
$"Unable to get stream for embedded resource '{sqlResourceFilename}' in assembly '{assembly.FullName}'.");
}
using var reader = new StreamReader(stream);
var sqlResult = reader.ReadToEnd();
migrationBuilder.Sql(sqlResult);
}
}
my tech lead and I were trying to figure out why I hadn't found a simple answer to inserting statements yet.我的技术主管和我试图弄清楚为什么我还没有找到插入语句的简单答案。 Neither was frustrated at the other, both were frustrated at the lack of simplicity we ran into.双方都没有对对方感到沮丧,他们都对我们遇到的缺乏简单性感到沮丧。
We found:我们发现:
All are valid or a good start, NONE are as simple as this:所有都是有效的或一个好的开始,NONE 就是这么简单:
I'll write the approach and post the code once I'm done.完成后,我将编写方法并发布代码。
You can create a helper method in same project first:您可以先在同一个项目中创建一个辅助方法:
public static string GetRawSql(string sqlFileName)
{
var baseDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Migrations");
var path = Path.Combine(baseDirectory, sqlFileName);
return File.ReadAllText(path);
}
And then add your migration.然后添加您的迁移。 Let's say you added as: add-migration AddDefaultUser
and then it generated as below:假设您添加为: add-migration AddDefaultUser
然后生成如下:
now add 2 sql files (incuding the SQL statement you want to run like an insert record etc..) with same name with postfix of _Up and _Down.现在添加 2 个 sql 文件(包括您想像插入记录一样运行的 SQL 语句等),名称相同,后缀为 _Up 和 _Down。 So it will be like:所以它会像:
Then in your migration file UP and DOWN methods, call them by using MigrationBuilder object.然后在您的迁移文件 UP 和 DOWN 方法中,使用 MigrationBuilder object 调用它们。 So your migration file will look like below:因此,您的迁移文件将如下所示:
public partial class AddDefaultUser : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql(SqlFileTrigger.GetRawSql("20220918043843_AddDefaultUser_Up.sql"));
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql(SqlFileTrigger.GetRawSql("20220918043843_AddDefaultUser_Down.sql"));
}
}
PS: MAKE SURE YOU SET YOUR SQL FILE PROPERTIES AS COPY ALWAYS
TO ENSURE THEY ARE DEPLOYED. PS:请确保将COPY ALWAYS
文件属性设置为始终以确保它们被部署。
Hope it helps..希望能帮助到你..
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.