Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-core/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何使用实体框架核心运行迁移SQL脚本_C#_Asp.net Core_Entity Framework Core_Entity Framework Migrations - Fatal编程技术网

C# 如何使用实体框架核心运行迁移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

我遇到了一个问题,无法访问SQL脚本来应用迁移。 这是我的迁移代码:

 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);
    
  • 此选项不太好,因为.sql将嵌入程序集中

  • 如果使用.csproj结构的Net Core项目,则可以将itemgroup添加到xml:

    <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

    首先,您需要创建一个迁移文件:

  • 在VisualStudio中,确保将web应用程序设置为启动项目
  • 在Visual Studio中打开PMC:View->Other Windows->Package Manager控制台(PMC)
  • 在PMC中,将默认项目设置为保存DbContext的项目(在我的例子中是.NET标准2.2库)
  • 添加新迁移:

    添加迁移RunSqlScript

  • 在迁移文件夹中添加一个Sql脚本(为了方便起见,我将其命名为与迁移文件相同的前缀)

    在“文件属性”窗口中,确保生成操作为“嵌入式资源” 请注意,我们不需要复制到输出文件夹,因为sql脚本将嵌入程序集中

    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);
      }
    }