在Ubuntu中构建SQL Server数据库项目

23
我正在构建一个ASP.NET Core 2.0 Web API应用程序,该应用程序托管在Ubuntu环境中。到目前为止,在Ubuntu中使.NET Core应用程序运行和构建方面我取得了巨大成功。
关于数据库,我的解决方案中包含一个SqlProj。该项目包括典型事物,如表格、存储过程和预/后部署脚本。我正在使用以下命令(在基于Windows的开发机器上)来构建和部署此项目:
msbuild .\MyProject.DB.sqlproj /t:Build /t:Publish /P:SqlPublishProfilePath="./PublishProfiles/MyProject.DB.publish.xml"

如果我采用这种方法,所有内容都能够正确构建和部署;然而,由于我将利用面向Ubuntu环境的.NET Core CLI命令+ CI/CD,所以我想做更多的事情:

dotnet msbuild .\MyProject.DB.sqlproj /t:Build /t:Publish /P:SqlPublishProfilePath="./PublishProfiles/MyProject.DB.publish.xml"

在Windows中,我立即收到错误提示:
error MSB4019: The imported project "C:\Program Files\dotnet\sdk\2.1.4\Microsoft\VisualStudio\v11.0\SSDT\Microsoft.Data.Tools.Schema.SqlTasks.targets" was not found. Confirm that the path in the <Import> declaration is correct, and that the file exists on disk.

基本上,我的问题是如何在Ubuntu环境中成功构建和部署SqlProj项目。我已经尝试过谷歌搜索,但到目前为止都没有任何进展。我找到的所有类似问题都是针对那些编辑.proj文件以定位他们VS文件夹中的SSDT的个人。所有这些人都在Windows中解决了这个问题。这种方法在Ubuntu中不起作用,因为目标文件使用Windows注册表键。
编辑:我知道使用MSBuild执行此类部署需要SSDT。我没有找到安装/使用SSDT甚至在Ubuntu上可能的证据。如果没有,也许有一种替代方案?
FYI,我知道使用EF Core的代码优先方法是可行的。我正在尝试采用原始SP方法(以及利用索引),并使用SqlProj跟踪我的所有代码。这将从Git存储库中存储并进行CI / CD处理。

你如何在Ubuntu上编译sqlproj?我无法解决msbuild错误。 - harsimranb
@harsimranb,我无法在Ubuntu上构建它。不幸的是,这就是问题所在。目前MSBuild对.SqlProj不起作用。我仍然没有找到解决办法。 - Brandon Avant
7个回答

5
Azure Data Studio现在有一个扩展,可以使用dotnet工具构建数据库项目(sqlproj)。构建项目的核心在于SQL Server Tools包,这是扩展获取所需的“BuildDirectory”DLL和目标依赖项的地方。
虽然没有记录,但如果您想在Azure Data Studio之外完全无头地设置此操作,则可以按照他们的CLI指南进行操作,https://learn.microsoft.com/en-us/sql/azure-data-studio/extensions/sql-database-project-extension-build-from-command-line?view=sql-server-ver15,但要从https://github.com/microsoft/sqltoolsservice/releases中的RHEL版本中提取必要的文件,然后遵循扩展的其余文档。以下是演示此方法的可行Dockerfile:
FROM mcr.microsoft.com/dotnet/sdk:6.0

WORKDIR /app

RUN apt-get update \
    && apt-get install -y curl

# SSDT dlls and targets file used by Azure Data Studio Extension can be found in the SQL Tools Service project
RUN curl -sSL -o /tmp/sqltools.tar.gz https://github.com/microsoft/sqltoolsservice/releases/download/v3.0.0-release.181/Microsoft.SqlTools.ServiceLayer-rhel-x64-net6.0.tar.gz

# Extract files that are required per https://learn.microsoft.com/en-us/sql/azure-data-studio/extensions/sql-database-project-extension-build-from-command-line?view=sql-server-ver15

RUN mkdir /tmp/sqltools && tar -xzf /tmp/sqltools.tar.gz -C /tmp/sqltools && \
  mkdir /app/BuildDirectory && cd /tmp/sqltools && cp \
    Microsoft.Data.SqlClient.dll \
    Microsoft.Data.Tools.Schema.Sql.dll \
    Microsoft.Data.Tools.Schema.SqlTasks.targets \
    Microsoft.Data.Tools.Schema.Tasks.Sql.dll \
    Microsoft.Data.Tools.Utilities.dll \
    Microsoft.SqlServer.Dac.dll \
    Microsoft.SqlServer.Dac.Extensions.dll \
    Microsoft.SqlServer.TransactSql.ScriptDom.dll \
    Microsoft.SqlServer.Types.dll \
    System.ComponentModel.Composition.dll \
    System.IO.Packaging.dll \
  /app/BuildDirectory && \
  rm -r /tmp/sqltools

#dotnet build your-database-project.sqlproj /p:NetCoreBuild=true /p:NETCoreTargetsPath="/app/BuildDirectory"

在最后注释的命令中,展示了你可以在容器内运行的命令,该容器位于你的数据库项目所在的目录。

这也可以与使用sqlpackage的容器相结合,实现完整的dacpac构建和发布自动化工具集。


5

所以这绝对是值得追求的道路。我已经开始研究采取这种方法的影响,但目前卡住了。我首先尝试将此包添加到我的 SqlProj 中,但我遇到了之前的错误加上“无法为项目'Myproject.sqlproj'创建依赖关系图文件。无法添加包引用。” 我也找不到任何证据(或指导)表明可以从 CLI 或 Linux 环境中实现这一点。难道没有人尝试过吗?我想我理解了,因为很多都是新的;所以有可能... - Brandon Avant
1
很遗憾,您无法将其添加为 SQL 项目的引用。您可以创建一个单独的“构建”项目,并通过 PowerShell 或命令行调用 SQLPackage。不确定它是否与 bash 或 .net core 兼容。 - nschonni
我会试一下。我唯一担心的是,从命令行调用msbuild似乎只会恢复到在我安装此包之前安装的内容(即VS MSBuild安装)。我该如何显式地调用Microsoft.Data.Tools.Msbuild包安装的程序集?在尝试在Ubuntu中执行此操作之前,我想确保我理解了这部分内容。 - Brandon Avant
不是很确定,因为我正在Windows上进行操作,并使用该软件包确保构建的DacPac部署使用正确/相同版本的SQLpackage,无论代理上安装了什么版本或未安装。但我可能是错的,我们可能已经更新了sqlproj以指向包文件夹内的.target文件。 - nschonni
好的。非常感谢迄今为止的帮助。在更好的解决方案出现之前,我将开始研究这条路线。一旦我遇到难题或找到解决方案,我会发布我的结果。 - Brandon Avant

3

我的2020解决方案

我希望在2020年重新审视这个问题并更新答案。

我采取了不同的方法来构建和部署SQL Server项目。我的当前方法是构建一个使用vs2017-win2016代理的管道,并使用它来构建.dacpac文件。从那里,您可以构建一个部署管道,将dacpac(从您的工件存储中)部署到SQL Server实例中。

这种方法更好地适应了DevOps方法,并消除了与我以前的解决方案相关的手动过程。

您可以在此处阅读更多信息:

https://learn.microsoft.com/en-us/azure/devops/pipelines/apps/aspnet/build-aspnet-dacpac?view=azure-devops


谢谢,看起来很有趣。我可以建议您接受自己的答案(毕竟这是您解决问题的方法),以使它更容易被未来的访问者看到吗? - Jan Hudec
@brandon-avant 但这只适用于Azure DevOps或Azure DevOps Server,对吧?我想如果想在Linux(或基于Linux的容器)上构建和部署项目,SDK解决方案会更好,不是吗? - Matze

3
作为替代方案,可以使用dotnet cli和sqlpackage来实现。在这里使用MSBuild Sdk进行解释。点击此处
您基本上拥有一个数据库项目,我们称之为“DatabaseProject”。
您创建了一个新项目,它是一个.NET标准C#库,您可以称其为“DatabaseProject.Build”。
然后,您可以将DatabaseProject.Build.csproj配置如下:
<Project Sdk="MSBuild.Sdk.SqlProj/1.11.4">
   <PropertyGroup>
       <TargetFramework>netstandard2.0</TargetFramework>
       <Configurations>Debug;Release</Configurations>
   </PropertyGroup>
   <ItemGroup>
       <Content Include="..\DatabaseProject\**\*.sql" />
       <Content Remove="..\DatabaseProject\bin\*.sql" />
       <Content Remove="..\DatabaseProject\**\*.PostDeployment.sql" />
       <PostDeploy Include="..\DatabaseProject\**\*.PostDeployment.sql" />
   </ItemGroup>
</Project>

请注意,本文编辑时所使用的版本为V1.11.4,支持Visual Studio附带的当前.NET SDK版本。请查看GitHub仓库以获取适用于您项目的最新NuGet版本。
使用dotnet build将生成一个dacpac文件,您可以将其与dotnet publish或sqlpackage一起使用。
然后,您可以发布到您的SqlServer实例。如果像我一样在CI中使用Linux运行程序,则可能需要SqlServer身份验证方法,然后运行以下命令:
sqlpackage /Action:Publish \    
/SourceFile:\"DatabaseProject.Build/bin/Debug/netstandard2.0/DatabaseProject.Build.dacpac\" \
/TargetServerName:MyDatabaseServerName \
/TargetDatabaseName:MyDatabaseName \
/TargetUser:Username\
/TargetPassword:Password

或者使用Visual Studio生成的配置文件:
sqlpackage /Action:Publish /Profile:\"DatabaseProject/PublishProfile/MyProfile.publish.xml\" /SourceFile:\"DatabaseProject.Build/bin/Debug/netstandard2.0/DatabaseProject.Build.dacpac\"

或者

dotnet publish /p:TargetServerName=MyServerName /p:TargetDatabaseName=MyDatabseName /p:TargetUser=<username> /p:TargetPassword=<password>

不错,这正是我最初要找的。我需要在某个时候尝试一下。 - Brandon Avant
1
我已经测试了第一部分(构建),它完美地工作。我的做法是在与我的.sqlproj文件相同的文件夹中创建一个.csproj文件。文件夹或子文件夹中的任何.sql文件都将包含在软件包中,因此请确保排除任何不应成为DACPAC一部分的脚本。 - Eduardo Hernández
这个解决方案使用了已经到达生命周期的donet 2.0(3.x也是)。你知道Linux上还有其他的解决方案吗?或者我最好忘记它,使用基于Windows的系统。 - Playing With BI
@PlayingWithBI 先生,我不确定您的意思是什么,您是指 .net 标准吗?如果是这样,它应该可以在当前最新版本的 dotnet 上运行。您可以在此处查看 https://learn.microsoft.com/en-us/dotnet/standard/net-standard#net-implementation-support。虽然我还没有在一个全新的 .net 5 项目上进行过实验,但 netstandard2.0 不应该有问题。如果您真的尝试了一下,我很想听听您的想法 =) - Xzemora
我使用MSBuild.Sdk.SqlProj SDK成功实现它,然后我添加了一个复杂的数据库项目,其中包括使用主数据库的安全性和视图,但我无法构建它。 - Playing With BI
1
@PlayingWithBI 嗯,我猜你使用了我当时提供的 Sdk="MSBuild.Sdk.SqlProj/1.3.0" 版本。它确实不支持 .net 5,导致你在构建方面遇到了问题。如果你去该项目的 Github 存储库,你会发现 nuget 包的版本现在是 V1.11.4,并且支持 .Net 5。所以请尝试使用 1.11.4 而不是 1.3.0。我希望它能解决你的构建问题。我也会更新我的答案。 - Xzemora

2
我不确定这是否适用于Ubuntu,但我们最近在一台没有安装SSDT的Windows构建机上通过了此操作,使用了上述NuGet包。突破口来自于下面文章中的细节拼接,特别是使用MSBuild的SDK需要设置环境变量才能正常工作。

https://blogs.msdn.microsoft.com/ssdt/2016/08/22/part-5-use-your-own-build-and-deployment-agent/

有了这些额外的信息,我们将NuGet包安装在解决方案文件夹的根目录中,然后编写了一个PowerShell构建脚本。该脚本首先设置环境变量,然后使用适当的输出目录调用SqlProj文件上的MSBuild。在这一点上,我们并没有特别发布,而是在我们的工作流程中将工件发布到Octopus Deploy中,以进行实际部署。

再次强调,我不确定这是否适用于Ubuntu,但认为这些额外的细节可能会有用。


谢谢Ryan。目前我们可能会在AWS设置中建立一个Windows Server虚拟机,并让它作为我们的构建代理。我承认,我还需要进行更多的研究来最终确定这个计划。你提供的信息以及之前的帖子应该会非常有益。我真的很感激。 - Brandon Avant

1

如前所述,在Linux代理上构建DacPac文件的最简单方法是通过MSBuild.Sdk.SqlProj完成。 进入数据库项目目录,与.sqlproj文件并行创建一个名为DB.Build的目录,在其中创建DB.Build.csproj,将以下内容复制并粘贴。

<Project Sdk="MSBuild.Sdk.SqlProj/1.1.0"> <!-- This will pull in the required tools and dependencies to build a .dacpac with .NET Core -->
    <PropertyGroup>
        <TargetFramework>netstandard2.0</TargetFramework>
    </PropertyGroup>
    <ItemGroup>
        <Content Include="..\src\DB\masterdata\**\*.sql" /> <!-- link in the new .csproj to the .sql scripts in your existing database project -->
    </ItemGroup>
</Project>

在运行后,您将看到dacpac文件出现在DB.Build/bin/Release/netstandard2.0/DB.Build.dacpac下。
这是我的构建代理输出(Azure DevOps上的Ubuntu代理)。
Starting: SQL DB build Release
==============================================================================
Task         : .NET Core
Description  : Build, test, package, or publish a dotnet application, or run a custom dotnet command
Version      : 2.187.0
Author       : Microsoft Corporation
Help         : https://learn.microsoft.com/azure/devops/pipelines/tasks/build/dotnet-core-cli
==============================================================================
Info: .NET Core SDK/runtime 2.2 and 3.0 are now End of Life(EOL) and have been removed from all hosted agents. If you're using these SDK/runtimes on hosted agents, kindly upgrade to newer versions which are not EOL, or else use UseDotNet task to install the required version.
/opt/hostedtoolcache/dotnet/dotnet build /home/vsts/work/1/s/src/RecommenderAPI.DB/RecommenderAPI.DB/RecommenderAPI.DB.Build/RecommenderAPI.DB.Build.csproj -dl:CentralLogger,"/home/vsts/work/_tasks/DotNetCoreCLI_5541a522-603c-47ad-91fc-a4b1d163081b/2.187.0/dotnet-build-helpers/Microsoft.TeamFoundation.DistributedTask.MSBuild.Logger.dll"*ForwardingLogger,"/home/vsts/work/_tasks/DotNetCoreCLI_5541a522-603c-47ad-91fc-a4b1d163081b/2.187.0/dotnet-build-helpers/Microsoft.TeamFoundation.DistributedTask.MSBuild.Logger.dll" --configuration Release /p:DeployOnBuild=true /p:WebPublishMethod=Package /p:PackageAsSingleFile=true /p:SkipInvalidConfigurations=true /p:PackageLocation=/home/vsts/work/1/recommender-service-cicd/DacPac/
Microsoft (R) Build Engine version 16.5.0+d4cbfca49 for .NET Core
Copyright (C) Microsoft Corporation. All rights reserved.

  Restore completed in 51.72 ms for /home/vsts/work/1/s/src/RecommenderAPI.DB/RecommenderAPI.DB/RecommenderAPI.DB.Build/RecommenderAPI.DB.Build.csproj.
  Using package name RecommenderAPI.DB.Build and version 1.0.0
  Using SQL Server version Sql150
  Deleting existing file /home/vsts/work/1/s/src/RecommenderAPI.DB/RecommenderAPI.DB/RecommenderAPI.DB.Build/obj/Release/netstandard2.0/RecommenderAPI.DB.Build.dacpac
  Writing model to /home/vsts/work/1/s/src/RecommenderAPI.DB/RecommenderAPI.DB/RecommenderAPI.DB.Build/obj/Release/netstandard2.0/RecommenderAPI.DB.Build.dacpac
  RecommenderAPI.DB.Build -> /home/vsts/work/1/s/src/RecommenderAPI.DB/RecommenderAPI.DB/RecommenderAPI.DB.Build/bin/Release/netstandard2.0/RecommenderAPI.DB.Build.dacpac

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:01.71

Finishing: SQL DB build Release


注意:在构建之前,请确保恢复您的NuGet包。

1
其他人经常建议的软件包R&R WFM's MSBuild.Sdk.SqlProj并不是来自微软,它并不能真正进行“真实的SSDT构建”。它不使用SSDT构建工具,而是一个独立的第三方工具,可以生成功能有限的DACPAC包。这些信息并不来自我对该工具的使用经验,而是在我试图研究我在DACPAC和Linux上还剩下哪些选项时,在某个地方读到的。虽然我无法以任何方式确认这些信息的真实性,但看起来是真实的,仓库中没有任何“Microsoft”标志,并且我在多个不相关的网站上读到了类似的警告,由据称是不同的人发布。

话虽如此,这是一个非常棒的工具,肯定需要大量的工作和知识。

但还有另一个工具。

最近,微软开始开发他们自己的跨平台 SSDT 构建工具 Microsoft.Build.Sql,源自 DacFx。在撰写本文时,它仍处于预览状态,当前版本为 0.1.10。如果你搜索如何使用该工具的文章,通常会看到 0.1.3 或 0.1.7 的版本。

微软提供了一个很好的指南,说明如何转换由 VisualStudio+SSDT 生成的现有 .sqlproj 文件。这篇文章简洁明了,但需要进行一些明显的修正。该文章还指向一个简约的新式 .sqlproj 文件,但链接已失效,不过该文件位于附近的一个文件夹中。

文章提到新式项目支持通配符(所以Include="folder/**/*.sql"代替列出所有文件),并且包含所有SQL文件已经是默认行为,因此像示例中的“空”项目文件将获取所有SQL文件 - 但要小心,并阅读关于与VisualStudio兼容性的最后一段。
根据这些信息,我成功地转换了我的.sqlproj文件。我按照那里解释的步骤进行操作,同时没有删除任何现在不再需要的文件包含,所以VS很满意。
我的.sqlproj文件现在看起来是这样的:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0">
  <!-- IMPORTANT: this is a PREVIEW tooling, keep an eye on changes and notes -->
  <!-- https://github.com/microsoft/DacFx/blob/main/src/Microsoft.Build.Sql/docs/Converting-Existing.md -->
  <Sdk Name="Microsoft.Build.Sql" Version="0.1.10-preview" />
  <PropertyGroup>
    <Name>xxxxxxxxxxxxxxxx</Name>
    <DSP>Microsoft.Data.Tools.Schema.Sql.Sql130DatabaseSchemaProvider</DSP>
    <ModelCollation>1033,CI</ModelCollation>
    <TargetDatabaseSet>True</TargetDatabaseSet>
    <DefaultCollation>Latin1_General_100_CI_AS</DefaultCollation>
  </PropertyGroup>
  <ItemGroup>
    <Folder Include="Properties" />
    <Folder Include="Tables" />
    <Folder Include="Views" />
    <Folder Include="Procedures" />
  </ItemGroup>
  <ItemGroup>
    <Build Include="Tables\xxxxxxxxx.sql" />
    <Build Include="Tables\xxxxxxxxx.sql" />
    <Build Include="Views\xxxxxxxxx.sql" />
    <Build Include="Views\xxxxxxxxx.sql" />
    <Build Include="Procedures\xxxxxxxxx.sql" />
    <Build Include="Procedures\xxxxxxxxx.sql" />
  </ItemGroup>
  <ItemGroup>
    <RefactorLog Include="xxxxxxxxx.refactorlog" />
  </ItemGroup>
  <ItemGroup>
    <PostDeploy Include="Script.PostDeployment1.sql" />
  </ItemGroup>
  <ItemGroup>
    <PreDeploy Include="Script.PreDeployment1.sql" />
  </ItemGroup>
  <ItemGroup>
    <None Include="xxxxxxxxx.publish.xml" />
  </ItemGroup>
</Project>

那个“xxx”部分当然只是匿名化。
我能够通过简单的方式成功构建这个项目并获得一个DACPAC文件。
cd solutionroot
dotnet build MyProject.sln

或者

cd solutionroot/dbproject
dotnet build MyProject.sqlproj

我不需要添加/p:NetCoreBuild=true - 在0.1.10的工具中,它会检测到是从dotnet命令运行,并自动设置这个参数。
这在我的本地开发机(Win10,VS2022,dotnet --version = 7.0.302)上构建时有效,也在CI代理(Amazon Linux 2)上运行时有效。
CI系统是AWS CodeBuild,使用的脚本如下:
version: 0.2    
phases:
  install:
    runtime-versions:
      dotnet: latest

  pre_build:
    commands:
      - dotnet --version
      - dotnet restore

  build:
    commands:
      - dotnet build -c Release

其实没什么大事发生。相关的输出部分如下:
[Container] 2023/07/08 20:36:06 Running command dotnet --version
6.0.408
(...snip...)
  xxxx.Database -> /codebuild/output/src3703237027/src/git-codecommit.eu-west-3.amazonaws.com/v1/repos/xxxx/xxxx/xxxx/bin/Release/xxxx.dll
  xxxx.Database -> /codebuild/output/src3703237027/src/git-codecommit.eu-west-3.amazonaws.com/v1/repos/xxxx/xxxx/xxxx/bin/Release/xxxx.dacpac

所以实际上花了6.0的时间,与我的本地环境不同。有点奇怪,但它仍然构建了dacpac。
值得注意的两件事情 - 虽然`dotnet build`能够构建DACPAC,但工具是“预览版”,如果我记得正确的话,GitHub上的文档提到并不支持所有功能。我不知道这些功能差距与rr-wfm的nuget包中的差距相比如何,但该工具仍在开发中,所以还有希望 :)
第二个需要注意的是,虽然`dotnet build`能够构建DACPAC,但`dotnet publish`无法运行它。尝试运行时会出错。
dotnet publish -c Release -p:SqlPublishProfilePath=./xxxx.publish.xml

最好的情况下,目前会出现以下错误。
/root/.nuget/packages/microsoft.build.sql/0.1.10-preview/tools/netstandard2.1/Microsoft.Data.Tools.Schema.SqlTasks.targets(1869,7): error MSB4018: The "SqlPublishTask" task failed unexpectedly.
/root/.nuget/packages/microsoft.build.sql/0.1.10-preview/tools/netstandard2.1/Microsoft.Data.Tools.Schema.SqlTasks.targets(1869,7): error MSB4018: System.PlatformNotSupportedException: Microsoft.Data.SqlClient is not supported on this platform.
/root/.nuget/packages/microsoft.build.sql/0.1.10-preview/tools/netstandard2.1/Microsoft.Data.Tools.Schema.SqlTasks.targets(1869,7): error MSB4018:    at Microsoft.Data.SqlClient.SqlConnectionStringBuilder..ctor(String connectionString)
/root/.nuget/packages/microsoft.build.sql/0.1.10-preview/tools/netstandard2.1/Microsoft.Data.Tools.Schema.SqlTasks.targets(1869,7): error MSB4018:    at Microsoft.Data.Tools.Schema.Common.SqlClient.SqlConnectionFactory..ctor(String connectionString)
/root/.nuget/packages/microsoft.build.sql/0.1.10-preview/tools/netstandard2.1/Microsoft.Data.Tools.Schema.SqlTasks.targets(1869,7): error MSB4018:    at Microsoft.Data.Tools.Schema.Sql.Deployment.CachedRegistryConnectionString..ctor(String connectionString, Boolean loadFromRegistry)

我在尝试在本地开发机器上运行dotnet publish(一切都正常),以及在CI代理服务器上尝试时,都遇到了此错误。

这是因为当前的0.1.10工具不支持dotnet publish命令。由于某种重要的内部原因,它可能根本不会得到支持。

除了dotnet publish之外,DacFx提供了一个单独的工具,称为SqlPackage。 它被宣传为运行DACPACs的跨平台工具

可以使用dotnet安装它:

dotnet tool install -g microsoft.sqlpackage

它可以发布DACPAC,但命令行语法略有不同(有关详细信息,请参见上面的链接):

SqlPackage /Action:Publish /SourceFile:".dacpac" /Profile:"....."

我还没有尝试安装和运行这个SqlPackage工具,但它看起来非常有前途。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接