使用Azure Pipeline任务进行EF迁移

时间:2020-01-16 01:01:16

标签: entity-framework powershell .net-core azure-devops azure-pipelines

在我看来,使用yaml构建管道来运行带有任务的迁移不是直截了当的,因为在尝试创建运行dotnet ef迁移的任务时遇到以下错误。

==============================================================================
Task         : PowerShell
Description  : Run a PowerShell script on Linux, macOS, or Windows
Version      : 2.151.1
Author       : Microsoft Corporation
Help         : https://docs.microsoft.com/azure/devops/pipelines/tasks/utility/powershell
==============================================================================
Generating script.
========================== Starting Command Output ===========================
##[command]"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -Command ". 'C:\agent\_work\_temp\a2cda363-57d3-416e-80ae-fb82a650ff74.ps1'"
Could not execute because the specified command or file was not found.
Possible reasons for this include:
  * You misspelled a built-in dotnet command.
  * You intended to execute a .NET Core program, but dotnet-ef does not exist.
  * You intended to run a global tool, but a dotnet-prefixed executable with this name could not be found on the PATH.
##[error]PowerShell exited with code '1'.
##[section]Finishing: Roll back migrations

在构建服务器上,我全局安装了dotnet-ef。因此,我现在不确定为什么会给我这个错误。以下是yml脚本。

- task: PowerShell@2
  displayName: "Apply migrations"
  inputs:
    targetType: 'inline'
    script: |
      dotnet ef database update --project $(Build.SourcesDirectory)\DataLayer\DataLayer

2 个答案:

答案 0 :(得分:2)

事实证明,这是Windows用户问题。 dotnet core 3不再在dotnet中内置了dotnet-ef,我知道这一点并将dotnet-ef安装为全局的,但显然这样做是用户在计算机上特定的。创建构建管道的开发人员需要与用户在同一台​​计算机上全局添加dotnet-ef才能正常工作。希望这对协作环境中的其他人有帮助。

答案 1 :(得分:0)

在我关注this文章之前,我有些困惑。使用CI / CD管道,EF​​迁移跨越了构建(CI)和部署(CD)之间的清晰界限。构建类似于烤披萨,并负责生成工件,而发行版则类似于交付披萨,并负责在目标上部署和安装工件。在AzureDevOps构建管道中运行ef database update就像试图传递仍在烤箱中的披萨一样-可能有用,但可能会烧掉汽车并使人们感到饥饿。

构建阶段无法知道将在何时何地使用工件,因此需要将它们与可能需要的所有东西一起打包。我们还希望能够在没有新版本的情况下自由部署到任何受支持的环境,以便我们能够根据需要做出反应(测试,高容量,灾难恢复等)。此外,只有发布阶段才能知道正确的数据库类型,其状态和机密,直到将其实际部署到目标服务器为止,因此任何数据库操作都应由其负责。

ef database update迁移命令执行两项任务:

  1. CI 任务,当它生成可使用活动配置中的连接设置在数据库上运行的脚本时。
  2. 一个 CD 任务,它将脚本应用于目标数据库。

因此,我们需要将ef迁移分为可以在适当模式下执行的不同任务。幸运的是,dotnet-ef提供了ef migrations script命令,用于将更新打包到一个文件中,该文件可以作为构建工件包括在内。我们还希望仅在需要时才运行迁移,而不是每次提交代码时都要擦除数据,因此 idempotent 标志正是我们所需要的:

幂等 (计算)描述一种动作,当多次执行时,第一次执行后对其主体没有进一步的影响。

棒极了,但是我们仍然需要运行dotnet-ef命令。与该文章一样,我在将 ef 命令作为 dotnet 任务运行时遇到问题,因此遵循建议并使用了基本的 script 命令。生成的yaml为:

steps:
- script: 'dotnet tool install --global dotnet-ef'
  displayName: Install dotnet EF
  
- script: 'dotnet ef migrations script   --idempotent  --output migrations.sql --project pathto\aproject.csproj'
  displayName: Create EF Scripts
 
- task: CopyFiles@2
  displayName: 'Copy EF Scripts to Staging'
  inputs:
    Contents: |
     **\migrations.sql 
    TargetFolder: '$(build.artifactstagingdirectory)'
    flattenFolders: true
    
- task: PublishBuildArtifacts@1
  displayName: 'Publish Artifact'
  inputs:
    PathtoPublish: '$(build.artifactstagingdirectory)'

然后在发行版中,每个阶段都需要将脚本应用于目标数据库。这种方法的真正功能是可以将同一内部版本推送到可以应用任何自定义配置的多个服务器或环境。在此示例中,开发Azure SQL实例:

- task: SqlAzureDacpacDeployment@1
  displayName: 'Execute EF Migrations'
  inputs:
    azureSubscription: '$(azureSubscription)'
    ServerName: '$(ServerName)'
    DatabaseName: '$(DatabaseName)'
    SqlUsername: '$(SqlUsername)'
    SqlPassword: '$(SqlPassword)'
    deployType: SqlTask
    SqlFile: '$(System.DefaultWorkingDirectory)\**\migrations.sql'  

现在,我们只需按一下按钮,就可以将我们的构建物可预期地部署到任何环境,并且我们有更多的时间来吃披萨(一旦完成交付)。