用powershell将dacpac转换成数据库对象的文件夹结构

Convert dacpac into folder structure of database objects with powershell

我正在努力将 SQL 服务器数据库集成到我们的内部版本 control/deployment 实用程序中,该实用程序是使用 powershell 构建的,并使用 Github 作为存储库。

使用出色的 sqlpackage.exe 实用程序,我已经能够添加一个过程,开发人员可以借此将他们当前的更改提取到 dacpac 中并将其存储在 Github 中,然后执行相反的操作当他们想要获得最新版本时。但是,由于 .dacpac 是二进制文件,因此无法在 git 中看到差异。我通过在存储在源代码管理中之前解压缩 dacpac 来缓解这种情况,因此添加了包含的 xml 文件。然而,即使这些文件是基于文本的,它们仍然不容易浏览和发现差异。

我想做的是将 dacpac 转换成类似于在 SSMS 中看到的文件夹结构(触发器、存储过程等所有数据库对象都在各自的文件夹中),将其存储在 Github,然后在客户端签出代码时将其转换回 dacpac。但是,sqlpackage.exe 中似乎没有任何功能,而且我找不到任何文档。我可以通过 Powershell 使用任何命令行工具吗?

基于另一个 post 我能够使脚本正常工作。警告是你必须尝试这些类型,直到你得到你想要的东西......它的方式不是它试图为某些对象放置完整的 http 或 https 值。

param($dacpacPath = 'c:\somepath' Debug', $dacpac = 'your.dacpac')
Add-Type -Path 'C:\Program Files (x86)\Microsoft SQL Server0\DAC\bin\Microsoft.SqlServer.Dac.dll'
add-type -path 'C:\Program Files (x86)\Microsoft SQL Server0\DAC\bin\Microsoft.SqlServer.Dac.Extensions.dll'
cd $dacpacPath
$dacPack = [Microsoft.SqlServer.Dac.DacPackage]::Load(((get-item ".$dacpac").fullname))
$model =[Microsoft.SqlServer.Dac.Model.TSqlModel]::new(((get-item ".$dacpac").fullname))
$queryScopes = [Microsoft.SqlServer.Dac.Model.DacQueryScopes]::All
$return = [System.Collections.Generic.IEnumerable[string]]
$returnObjects = $model.GetObjects([Microsoft.SqlServer.Dac.Model.DacQueryScopes]::All)
$s = ''
foreach($r in $returnObjects)
{
   if ($r.TryGetScript([ref]$s))
   {
    $objectTypeName = $r.ObjectType.Name;
    $d="c:\temp\db$objectTypeName"
    if(!(test-path $d ))
    {
        new-item $d -ItemType Directory
    }
    $filename = "$d$($r.Name.Parts).sql"

    if(! (test-path $filename))
    {new-item $filename -ItemType File}
    $s | out-file  $filename -Force
    write-output $filename
   }

}

使用 DacFx 的 public API,您可以加载 dacpac,迭代所有对象,并编写每个对象的脚本。如果您愿意编写自己的代码,您可以根据对象类型将每个代码写入其自己的文件。 model filtering samples in the DacExtensions Github project. Specifically you'll want to do something like the ModelFilterer code that loads a dacpac, queries all objects, scripts them out - see the CreateFilteredModel 方法中涵盖了基本过程。我在下面放了一个应该主要工作的示例。一旦你有了这个,你就可以很容易地在 per-object 的基础上进行比较。

using (TSqlModel model = new TSqlModel(dacpacPath))
{
    IEnumerable<TSqlObject> allObjects = model.GetObjects(QueryScopes);
    foreach (TSqlObject tsqlObject allObjects)
    {
        string script;
        if (tsqlObject.TryGetScript(out script))
        {
            // Some objects such as the DatabaseOptions can't be scripted out.

            // Write to disk by object type
            string objectTypeName = tsqlObject.ObjectType.Name;
            // pseudo-code as I didn't bother writing.
            // basically just create the folder and write a file
            this.MkdirIfNotExists(objectTypeName);
            this.WriteToFile(objectTypeName, tsqlObject.Name + '.sql', script);
        }
    }
}

这可以很容易地转换成 powershell cmdlet。 dacfx 库位于 https://www.nuget.org/packages/Microsoft.SqlServer.DacFx.x64/ 的 nuget 上,因此您应该能够在 PS 中安装它们,然后使用代码不会遇到太多麻烦。