使用PowerShell将dacpac转换为数据库对象的文件夹结构

时间:2018-03-02 17:42:21

标签: sql-server powershell sql-server-data-tools dacpac

我正在努力将SQL Server数据库集成到我们的内部版本控制/部署实用程序中,该实用程序使用powershell构建,并使用Gi​​thub作为存储库。

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

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

2 个答案:

答案 0 :(得分:2)

使用DacFx的公共API,您可以加载dacpac,遍历所有对象,并为每个对象编写脚本。如果您愿意编写自己的代码,可以根据对象类型将每个代码写入自己的文件中。 DacExtensions Github项目中的model filtering samples涵盖了基本过程。具体来说,您需要执行类似于加载dacpac的ModelFilterer代码,查询所有对象,将其编写出来的内容 - 请参阅CreateFilteredModel方法。我已经放了一个应该在下面工作的样本。完成后,您可以轻松地按对象进行比较。

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/,因此您应该可以在PS中安装它们,然后使用代码而不会有太多麻烦。

答案 1 :(得分:0)

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

param($dacpacPath = 'c:\somepath' Debug', $dacpac = 'your.dacpac')
Add-Type -Path 'C:\Program Files (x86)\Microsoft SQL Server\120\DAC\bin\Microsoft.SqlServer.Dac.dll'
add-type -path 'C:\Program Files (x86)\Microsoft SQL Server\120\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
   }

}