将数据库脚本打包到部署程序中,是最常用的做法之一。当然,其他方法还有,比如将备份文件打包,然后在安装的时候还原数据库。比如,将MDF和LDF打包,安装的时候,直接附加,也可以不打包数据库,手动部署,这要根据你的项目需求来说。
今天我主要写以执行脚本创建数据库这种方式来打包数据库。
明确一下写Blog的目的,主要是当作笔记,来记录自己做过的事情,应该注意的事情,细节等。请不要将本blog文章用于商业,必将追究法律责任!欢迎转载,请注明出处【开发笔记-Rain】。谢谢
第一步:创建数据库脚本
打开您的Sql Studio,创建如下脚本,并保存到Setup.sql
这里,假设是您项目中的数据库脚本,真实脚本情况,要根据你的具体项目,这里仅作演示使用。
第二步:打开Visual studio,并创建部署项目
如果你对部署不了解,请参照上一篇
我们创建了2个项目,分别是演示程序和部署程序
双击选择Form1,在设计界面拖放一个DataGridView。
为了编程的方面,我将其重新命名,窗体命名为 FrmTest, dtaGridView1命名为dgvTest
本程序以SQL Server 为数据库实例,请引入相应的程序集和名称空间
在测试项目中,添加App.Config,我们需要从这里获取ConnectionString
并在App.config里录入配置信息
选择窗体,按F7切换到Code,代码如下
如果您已经创建了数据库,这时候运行程序,会正常得到要显示的数据。不过,这不是重点!
接下来,我们再创建一个项目,选择ClassLibrary,并将其命名为SetupDataBase,删除默认的Calss1,新加一个Installer Class,并将Installer1改名为SetupDb并继承System.Configuration.Install.Installer。
我们需要特别注意下面四个方法。
•Install — 在安装步骤调用。
•Commit — 完成安装过程。
•Rollback — 将系统还原为安装前的状态。在 Install 步骤失败时调用 Rollback。通常,在重写该方法时,它应该执行与卸载相同的任务。
•Uninstall — 删除已经安装的文件,并重置/删除在安装过程中完成的任何配置。如果此步骤失败,通常无法还原到安装前的状态。
我们这次只选第一个作为演示,其他的由您来发挥!
在程序Install 时,我们将执行脚本文件,同时更新App.Config内的ConnectionString,以确保程序“傻瓜式”安装。
不过,在这之前,我们还要做一件事情 -- 设计安装界面,即,在安装界面输入数据库的一些基本信息,以供我们在安装时收集。
按照下面操作,打开Interface
将新加的Textboxs(A)拖到Installtion Folder之前,并右击,点击属性:
BannerText:要为该屏幕显示的标志。
Edit1Label:第一个文本框的标签。设置为 Server Name。查找其他标签属性,并相应地进行设置。
Edit1Property:该属性非常重要:此处提供的名称要在 Custom Actions 中访问。将该属性设置为 SERVER_NAME。同样地,为示例中显示的其他属性设置 DATABASE_NAME、USER_NAME 和 PASSWORD。
Edit1Value:要设置为默认值的值。您可以指定可用的默认属性。例如,[ComputerName] 会将此文本框的默认值设置为用户计算机的名称。
Edit1Visible:此值有助于您控制文本框的可见性。对于此示例,所有属性均为真。
OK,界面设计完成。
下面一个重要的命令程序要出场了 ,那就是OSQL.exe
有关OSQL的解释,请查阅这里
简单的说,OSQL可以执行脚本。
有关OSQL的参数,请在命令行里输入 osql /?
本实例将会用到
osql [-S 服务器名称] [-d 数据库名称][-U 用户名] [-P 密码][-i 脚本所在的绝对路径] [-o 日志文件输出路径]
osql [-S 服务器] [-d 数据库名][-E 受信连接][-i 脚本所在的绝对路径] [-o 日志文件输出路径]
将脚本文件“setup.sql“拷贝到 SetupDataBase 项目下,并设置属性 Bulid Action:Content
选择刚刚创建的SetupDataBase,进入代码编辑界面,如下:(代码中已经包含必要的注释,这里不做详细解释)
(PS:代码过长,显示的不好看 - - )
SetupDb.cs
[RunInstaller(true)]
public partial class SetupDb : Installer
{
public SetupDb()
{
InitializeComponent();
}
public override void Install(IDictionary stateSaver)
{
base.Install(stateSaver);
const string server = "server";
const string database = "database";
const string username = "username";
const string password = "password";
const string target = "target";
const string fileName = "Setup.sql";
var isTrustedConnection = false;
//Get paramters from UserInterface Action
//Set DictionaryEntry Size
var myArr = new DictionaryEntry[Context.Parameters.Count];
//From StringDictionary to DictionaryEntry
Context.Parameters.CopyTo(myArr, 0);
//Add configuration to *.InstallState
//If you remove the program will be used it.
for (var i = 0; i < myArr.Length; i++)
{
stateSaver.Add(myArr[i].Key, myArr[i].Value);
//MessageBox.Show(myArr[i].Key + " = " + myArr[i].Value);
}
Func<string, string> select = key => myArr.Single(t => t.Key.Equals(key)).Value.ToString();
// Evaluate connectionstring based on input
var serverName = select(server);
var databaseName = select(database);
var userName = select(username);
var userPwd = select(password);
var targetName = select(target);
var connectionString = "Data Source=" + serverName;
connectionString += ";Initial Catalog=" + databaseName;
//test the connection.
var sqlConnection = new SqlConnection();
if (!userName.Equals(string.Empty))
{
sqlConnection.ConnectionString = "Data Source=" + serverName + ";Initial Catalog=master;User Id=" + userName + ";Password=" + userPwd;
sqlConnection.Open();
sqlConnection.Close();
sqlConnection.Dispose();
connectionString += ";User ID=" + userName;
connectionString += ";Password=" + userPwd;
}
else
{
sqlConnection.ConnectionString = "Data Source=" + serverName + ";Initial Catalog=master;trusted_connection=yes";
sqlConnection.Open();
sqlConnection.Close();
sqlConnection.Dispose();
isTrustedConnection = true;
//If you remove the program will be used it.
stateSaver.Add("trustedconnection", true);
connectionString += ";Trusted_connection=yes";
}
//Set the Config file's connection string
var xmlDocument = new XmlDocument();
var xmlPath = targetName + "WindowsFormsApplication.exe.config";
//MessageBox.Show(xmlPath);
xmlDocument.Load(xmlPath);
var connectionNode = xmlDocument.SelectSingleNode(
@"configuration/connectionStrings/" + @"add[@name='SetupConnection']");
//MessageBox.Show(connectionNode.Attributes["connectionString"].Value);
if (null == connectionNode) throw new InstallException("Configuration file had no node declared for connection string.");
connectionNode.Attributes["connectionString"].Value = connectionString;
//MessageBox.Show(connectionString);
xmlDocument.Save(xmlPath);
//Run SQL Script next
DbInstaller.RunDbScript(targetName,userPwd,userName,serverName,isTrustedConnection,fileName,databaseName);
}
}
DbInstaller.cs
class DbInstaller
{
public static void RunDbScript(string targetPath, string password, string userName, string serverName, bool trustedconnection, string fileName,string databaseName)
{
ChangeDataBaseName(targetPath + fileName, databaseName, "CONST_DATBASE_PLACEHOLDER");
var processInfo = new ProcessStartInfo
{
WindowStyle = ProcessWindowStyle.Hidden,
FileName = "osql.exe",
Arguments = GetProcessArguments(targetPath, password, userName, serverName,trustedconnection, fileName, "master")
};
var osql = Process.Start(processInfo);
if (osql != null) osql.WaitForExit();
if (osql != null) osql.Dispose();
}
static string GetProcessArguments(string targetPath,string password,string userName,string serverName,bool trustedconnection,string fileName, string overridendatabasename)
{
//Check for trusted connection.
if (!trustedconnection)
return " -S " + serverName + " -d " + overridendatabasename + " -U " + userName + " -P " + password + " -i " + Char.ToString('"') + targetPath + fileName + Char.ToString('"') + " -o " + Char.ToString('"') + targetPath + "Log.txt" + Char.ToString('"');
return " -S " + serverName + " -d " + overridendatabasename + " -E " + " -i " + Char.ToString('"') +targetPath + fileName + Char.ToString('"') + " -o " + Char.ToString('"') + targetPath + "Log.txt" + Char.ToString('"');
}
static void ChangeDataBaseName(string filepath, string databaseName, string placeHolder)
{
var reader = new System.IO.StreamReader(filepath);
var content = reader.ReadToEnd();
reader.Close();
content = content.Replace(placeHolder, databaseName);
var writer = new System.IO.StreamWriter(filepath, false);
writer.Write(content);
writer.Flush();
writer.Close();
}
}
选择部署项目,右键 Add –> Project output
将解决方案中的两个项目的主输出和内容都加入。
Ctrl + shift + B 编译
到此,还差最后一步
选择部署项目,右键,选择 View –> Custom Actions
然后点击 Install 下的 Primary output from SetupDataBase (Active),右键,选择属性,在属性窗口中的Custom Actions Data,作下图的设置:
/server=[SERVER_NAME]
/target="[TARGETDIR]\"
/database=[DATABASE_NAME]
/username=[USER_NAME]
/password=[PASSWORD]
到此,打包数据库脚本并执行脚本完成
测试通过