我有一个安装数据库的安装程序。数据库与某些登录名一起创建。为了创建登录名,我在 SqlString 元素中使用了 master 数据库。对 master 数据库的访问权限仅授予在 SQL 服务器上具有非常高权限的用户。通常,安装会中止,因为为 master 数据库指定的 SQL 字符串由于缺少权限而无法执行。
我想编辑我的安装程序,以便在无法执行 SqlString 元素时,应跳过安装的 SQL 部分。安装完成后,我希望用户能够自己执行SQL语句。我的安装程序执行的每个 SQL 操作都存储在 SqlString 元素中。SqlString 元素包含许多属性,这些属性在安装过程中会被替换。我想将所有编辑过的 SqlString 元素的内容提取到存储在用户目录中的一个 sql 文件中。
我想我将不得不编写一个自定义操作,该操作在 sqlextension 替换属性后发生。然后我将不得不访问这些更改的字符串。有什么办法可以做到这一点吗?
示例 SqlString 元素:
<sql:SqlDatabase Id="MasterDB" Server="[SQLSERVER_SERVER]" Instance="[SQLSERVER_INSTANCENAME]" Database="master" />
<sql:SqlString
SqlDb="MasterDB"
Id="CreateNetworkServiceAccount"
ExecuteOnInstall="yes"
ContinueOnError="no"
SQL="IF NOT EXISTS (SELECT * FROM sys.server_principals WHERE name = N'{[WIX_ACCOUNT_NETWORKSERVICE]}')
CREATE LOGIN [[]{[WIX_ACCOUNT_NETWORKSERVICE]}[]] FROM WINDOWS WITH DEFAULT_DATABASE=[[]master[]]"
Sequence="101"/>
我想在 SqlString 失败后拥有的 sql 文件示例:
USE master;
IF NOT EXISTS (SELECT * FROM sys.server_principals WHERE name = N'NT AUTHORITYNetwork Service')
CREATE LOGIN [NT AUTHORITYNetwork Service] FROM WINDOWS WITH DEFAULT_DATABASE=[master]
我用一个相当奇怪的解决方案解决了这个问题。我编写了一个自定义操作,它从 SqlString 表中提取字符串元素,然后将格式化字段替换为存储在会话中的相应属性。要访问会话变量,自定义操作必须按immediate
执行。我已经安排了它,以便在InstallFinalize
获得访问PersonalFolder
属性的权限。使用此属性,我可以将 SqlScript 表中的条目生成的 Sql 脚本存储在用户文档目录中。为了考虑安装中的不同数据库,我在 SqlDatabase 表中包含一个查找。
下面是自定义操作的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Deployment.WindowsInstaller;
using System.IO;
using System.Text.RegularExpressions;
namespace SaveSqlStrings
{
public class CustomActions
{
[CustomAction]
public static ActionResult SaveSqlStrings(Session session)
{
StringBuilder sqlStrings = new StringBuilder();
Database db = session.Database;
View view = db.OpenView("SELECT * FROM `SqlString`");
IList<string> SqlStringElements = db.ExecuteStringQuery("SELECT `String` FROM `SqlString`");
Regex bracketedProperties = new Regex(@"[(b[A-Z_]*b)]");
Regex formattedProperties = new Regex(@"{[(b[A-Z_]*b)]}");
Regex openeningSquareBrackets = new Regex(@"[\[]");
Regex closingSquareBrackets = new Regex(@"[\]]");
string sqlDb_ = "";
string sqlString = "";
string Database = "";
foreach (string dbString in SqlStringElements)
{
sqlDb_ = (string)db.ExecuteScalar("SELECT `SqlDb_` FROM `SqlString` WHERE `String` ='{0}'",dbString);
sqlString = (string)db.ExecuteScalar("SELECT `SQL` FROM `SqlString` WHERE `String` ='{0}'",dbString);
view.Close();
view = db.OpenView("SELECT * FROM `SqlDatabase`");
Database = (string)db.ExecuteScalar("SELECT `Database` from `SqlDatabase` WHERE `SqlDb`='{0}'", sqlDb_);
if(bracketedProperties.IsMatch(Database))
{
Database = bracketedProperties.Match(Database).Groups[1].Value;
Database = session[Database];
}
if (openeningSquareBrackets.IsMatch(sqlString))
sqlString = openeningSquareBrackets.Replace(sqlString, "[");
if (closingSquareBrackets.IsMatch(sqlString))
sqlString = closingSquareBrackets.Replace(sqlString, "]");
if(formattedProperties.IsMatch(sqlString))
{
string propertyName = formattedProperties.Match(sqlString).Groups[1].Value;
string propertyValue = session[propertyName];
sqlString = formattedProperties.Replace(sqlString, propertyValue);
}
sqlStrings.AppendLine(String.Format("use {0}",Database));
sqlStrings.AppendLine(sqlString);
}
string home = session["PersonalFolder"];
string sqlPath = string.Concat(home, @"Script.sql");
try
{
File.WriteAllText(sqlPath, sqlStrings.ToString());
}
catch (Exception ex)
{
session["FailedTowrite"] = sqlPath;
}
view.Close();
db.Close();
return ActionResult.Success;
}
}
}