2

我需要在使用 WIX 安装数据库时部署 dacpac。为此,我考虑使用必要的开关运行 SQLPackage.exe 命令,因此我使用二进制标记嵌入了必要的 exe 和 dll,如下所示

<Binary Id="Microsoft.Data.Tools.Schema.Sql.dll" SourceFile="..\DeployDBs\DAC\Microsoft.Data.Tools.Schema.Sql.dll"/>
    <Binary Id="Microsoft.Data.Tools.Schema.Tasks.Sql.11.dll" SourceFile="..\DeployDBs\DAC\Microsoft.Data.Tools.Schema.Tasks.Sql.11.dll"/>
    <Binary Id="Microsoft.Data.Tools.Schema.Utilities.Sql.11.dll" SourceFile="..\DeployDBs\DAC\Microsoft.Data.Tools.Schema.Utilities.Sql.11.dll"/>
    <Binary Id="Microsoft.Data.Tools.Utilities.dll" SourceFile="..\DeployDBs\DAC\Microsoft.Data.Tools.Utilities.dll"/>
    <Binary Id="Microsoft.SqlServer.Dac.dll" SourceFile="..\DeployDBs\DAC\Microsoft.SqlServer.Dac.dll"/>
    <Binary Id="SqlPackage" SourceFile="..\DeployDBs\DAC\SqlPackage.exe"/>
    <Binary Id="SqlPackage.exe.config" SourceFile="..\DeployDBs\DAC\SqlPackage.exe.config"/>

并使用自定义操作调用 SqlPackage.exe,如下所示

 <CustomAction Id="DeployMyDb" BinaryKey="SqlPackage" 
              ExeCommand="/a:publish /sf:&quot;MyDacpac.dacpac&quot; /tsn:localhost /tdn:MyDb" 
              Execute="immediate" />

自定义操作是在“InstallFinalize”之后运行的序列,如下所示

<InstallExecuteSequence>
      <Custom Action="DeployMyDb" After="InstallFinalize"/>
    </InstallExecuteSequence>
    </Product>

部署 dacpac 时(即运行自定义操作),它会为程序集“Microsoft.Data.Tools.Utilities”抛出“FileNotFoundException”,该程序集是嵌入式二进制文件之一。

请就运行此 exe 所需完成的缺失步骤或添加事项提供建议。

4

2 回答 2

3

我找到了解决方案。

代替上述方法,我为自定义操作创建了一个单独的项目,并添加了对所需二进制文件的引用(即我之前在 <binary> 标记中提到的二进制文件),并添加了二进制标记中形成的相应 dll 并通过 <CustomAction 调用它>

得到的解决方案如下:

<Binary Id="InstallerWix_CustomAction.CA.dll" SourceFile="..\InstallerWix_CustomAction\bin\Debug\InstallerWix_CustomAction.CA.dll" />

<CustomAction Id="DeployDb" BinaryKey="InstallerWix_CustomAction.CA.dll" 
                 DllEntry="CustomAction1"                   
                  Execute="immediate" Return="check" />

<InstallExecuteSequence>
  <Custom Action="DeployDb" After="InstallFinalize"/>
</InstallExecuteSequence>
于 2014-09-03T04:23:05.163 回答
3

我能够通过将 dacpac 文件添加为二进制文件、在 CustomAction 中读取该二进制文件并最终在我的 C# 自定义操作中使用“Microsoft.SqlServer.Dac”(可在 nuget 上获得)来实现这一点。

我必须将二进制文件流写入 MemoryStream 以与 DacPac.Load 函数一起使用。二进制流是 Load 函数无法使用的“RecordStream”的内部类型。出于您的目的,您可能还想修改 dacOptions 变量以获得所需的结果。

请参阅下面的示例:

项目.wxs:

<Binary Id="Database.dacpac" SourceFile="$(var.ProjectDir)\Database.dacpac" />

<CustomAction Id="DeployDacpac" BinaryKey="CustomAction.dll" DllEntry="DeployDacpac" Execute="immediate" />

<InstallExecuteSequence>
  <Custom Action="DeployDacpac" After="InstallFinalize" />
</InstallExecuteSequence>

CustomAction.cs:

[CustomAction]
    public static ActionResult DeployDacpac(Session session)
    {
        try
        {
            string sql = string.Format("SELECT Data FROM Binary WHERE Name = 'Database.dacpac'");

            View view = session.Database.OpenView(sql);

            view.Execute();
            var dataStream = view.First()["Data"] as Stream;
            byte[] buffer = new byte[dataStream.Length];
            int bytesRead;
            while ((bytesRead = dataStream.Read(buffer, 0, buffer.Length)) > 0) ;
            using (MemoryStream ms = new MemoryStream(buffer))
            {
                var dacOptions = new DacDeployOptions();
                dacOptions.BlockOnPossibleDataLoss = false;
                dacOptions.DropDmlTriggersNotInSource = false;
                dacOptions.DropObjectsNotInSource = false;

                var dacServiceInstance = new DacServices(GenerateConnectionString(session["SQLSERVER"], session["SQLDATABASE"], session["SQLUSER"], session["SQLPASSWORD"]));
                using (DacPackage dacpac = DacPackage.Load(ms))
                {
                    dacServiceInstance.Deploy(dacpac, session["SQLDATABASE"], upgradeExisting: true, options: dacOptions);
                }
            }
        }
        catch (Exception ex)
        {
            session.Log(ex.Message);
            return ActionResult.Failure;
        }
        return ActionResult.Success;
    }
于 2015-08-06T15:41:48.767 回答