C# 如何使用实体框架核心运行迁移SQL脚本
我遇到了一个问题,无法访问SQL脚本来应用迁移。 这是我的迁移代码:C# 如何使用实体框架核心运行迁移SQL脚本,c#,asp.net-core,entity-framework-core,entity-framework-migrations,C#,Asp.net Core,Entity Framework Core,Entity Framework Migrations,我遇到了一个问题,无法访问SQL脚本来应用迁移。 这是我的迁移代码: public partial class AddSomethingMigration : Migration { private const string MIGRATION_SQL_SCRIPT_FILE_NAME = @"Migrations\Scripts\20170710123314_AddSomethingMigration.sql"; protected override void Up(Mig
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));
}
}
因此,当我在本地机器上使用包管理器控制台时,一切正常。但是,当我部署到环境中时,我会将差异添加到文件中
我可以通过EF迁移自动运行静态SQL脚本吗,还是应该将SQL查询内联粘贴到代码中?我找到了这个问题的几个答案
string sql = Resources._20170630085940_AddMigration;
migrationBuilder.Sql(sql);
<ItemGroup> <Content Include="Migrations\**\*.sql" CopyToPublishDirectory="PreserveNewest" /><!-- CopyToPublishDirectory = { Always, PreserveNewest, Never } --></ItemGroup>
我喜欢做的是将SQL脚本作为资源嵌入程序集中,这样程序集就不依赖于任何外部文件。我已经用VisualStudioCommunity201916.4.2测试了这种方法。 在我的例子中,
DbContext
保存在.NET标准2.0库中,我的web应用程序运行的是.NET Core 2.2
首先,您需要创建一个迁移文件:
添加迁移RunSqlScript
RunSqlScript
迁移中更新Up方法
var assembly = Assembly.GetExecutingAssembly();
string resourceName = typeof(RunSqlScript).Namespace + ".20191220105024_RunSqlScript.sql";
using (Stream stream = assembly.GetManifestResourceStream(resourceName))
{
using (StreamReader reader = new StreamReader(stream))
{
string sqlResult = reader.ReadToEnd();
migrationBuilder.Sql(sqlResult);
}
}
在我的应用程序中,我已将此代码重新分解为一个实用方法。为了简洁起见,我在没有重新分解的情况下发布了这篇文章
更新:
我上面提到的重新分解代码:
公共静态类迁移实用程序
{
///
///读取嵌入到资源中的SQL脚本。
///
///SQL文件脚本附加到的迁移类型。
///嵌入的SQL文件名。
///SQL文件的内容。
公共静态字符串ReadSql(类型migrationType,字符串sqlFileName)
{
var assembly=migrationType.assembly;
字符串resourceName=$“{migrationType.Namespace}.{sqlFileName}”;
使用(Stream=assembly.GetManifestResourceStream(resourceName))
{
if(流==null)
{
抛出new FileNotFoundException(“无法从嵌入式资源中找到SQL文件”,resourceName);
}
使用(变量读取器=新的流读取器(流))
{
字符串内容=reader.ReadToEnd();
返回内容;
}
}
}
}
用法示例:
string sql=MigrationUtility.ReadSql(typeof(RunSqlScript),“20191220105024_RunSqlScript.sql”);
Sql(Sql);
这是使用嵌入式资源的方法的升级。其主要思想是使用抽象类和与迁移同名的sql文件
公共抽象类SqlMigration:迁移
{
受保护的密封覆盖作废(MigrationBuilder MigrationBuilder)
{
var assembly=assembly.getExecutionGassembly();
var type=GetType();
var regex=new regex($@“{regex.Escape(type.Namespace)}\。{{14}}}{regex.Escape(type.Name)}\.sql”);
var resourceName=assembly.GetManifestResourceNames().FirstOrDefault(x=>regex.IsMatch(x));
使用var stream=assembly.GetManifestResourceStream(resourceName);
使用var reader=newstreamreader(流);
var sqlResult=reader.ReadToEnd();
Sql(sqlResult);
}
}
它只为正则表达式使用实数类型的名称和命名空间。
继承类将如下所示:
公共部分类RunSqlScript:SqlMigration
{
受保护的覆盖无效关闭(MigrationBuilder MigrationBuilder)
{
//下面是代码
}
}
项目将类似于:
.类似:谢谢你的回答,史蒂夫。但这对我不起作用。因为我在本地计算机和主机之间有不同的路径。问题可能与此相关。代码的用途是什么?这些是CopyTopPublishDirectory的选项吗?@shkapo,如果我理解正确的话,方法1是将SQL查询放入resx文件中。首先,我不喜欢这样,因为.resx不容易编辑:我更喜欢在VisualStudio中有一个.sql文件。第二,我不明白你为什么说把SQL嵌入程序集中是不好的。我不希望程序集依赖于SQL文件,您能详细说明一下吗?签出我提交的答案,让我知道你的想法。@Yanal YvesFargialla你可以将该文件作为资源添加到项目中。因此,它仍然在自己的.sql文件中,然后您将该文件添加为resource.Thx(本例中为resource.Thx)。但是,您的代码片段并不反映您的屏幕截图:string resourceName=typeof(RunSqlScript).Namespace+“.20191220105024_RunSqlScript.sql”;抓到了@Umar3x!我最初的回答是:对于EF4。当我回答EF core的同等问题时,在发布和复制/超过实际代码之前,我已经在VS 2019 16.4.2上对其进行了测试。但是,我很懒,我重新使用了我最初答案的屏幕截图。我非常喜欢这种方法,我想看看你的重新分解方法。@c0y0teX,我已经用重新分解的代码更新了我的anwser。我希望这能有所帮助。非常感谢您的更新。
var assembly = Assembly.GetExecutingAssembly();
string resourceName = typeof(RunSqlScript).Namespace + ".20191220105024_RunSqlScript.sql";
using (Stream stream = assembly.GetManifestResourceStream(resourceName))
{
using (StreamReader reader = new StreamReader(stream))
{
string sqlResult = reader.ReadToEnd();
migrationBuilder.Sql(sqlResult);
}
}