应用程序部署期间恢复数据库
使用Windows Installer和Visual Studio安装项目在应用程序部署期间恢复数据库
引言
在.NET开发的应用程序中,数据存储通常使用MS SQL Server。在应用程序分发过程中,一个常见的问题是如何在目标计算机(您的项目将安装的PC或工作站)上安装数据库。
本文介绍的方法允许在应用程序安装阶段执行“还原数据库”操作。
应用程序和数据库开发
首先创建一个与数据库交互的应用程序。
创建一个名为“SampleDatabase
”的示例数据库。
创建一个连接到已创建数据库并检索数据的示例应用程序。
(“SampleApplication”在随本文提供的文件中。)
创建安装程序
现在,我们来创建一个安装程序。
- 首先,我们需要在“SQL Server Management Studio Express”中为数据库创建备份,方法是选择所需的数据库并单击“Back Up…”
- 然后选择路径和备份副本文件名。在本例中是“SampleDatabase.bak”。
- 然后选择路径和备份副本文件名。在本例中是“SampleDatabase.bak”。
- 接下来,我们创建一个自定义操作。
- 虽然标准操作在大多数情况下足以执行安装,但自定义操作允许安装包的作者通过包含可执行文件、动态链接库和脚本来扩展标准操作的功能。
- 使用类库模板创建一个新项目,然后在“Name”框中键入“
SampleInstallLib
”,在“Solution Name”框中键入“SampleInstallApp
”,然后单击OK。项目已添加到解决方案资源管理器中。
- 在“Project”菜单上,选择“Add Class”,然后在“Add New Item”对话框中,选择“
Installer
Class”。接受默认名称Installer1.cs。单击Add。 - 通过展开解决方案资源管理器,右键单击Class1.cs对象并选择“Delete”选项,从
SampleInstallLib
项目中删除默认的Class1.cs对象。 - 然后打开Installer1.cs进行编辑。
添加引用
Microsoft.SqlServer.ConnectionInfo Microsoft.SqlServer.Smo System.Windows.Forms
您将需要以下命名空间才能使上面的代码正常工作
using System.Data.SqlClient; using System.IO; using System.Security.AccessControl; using System.Windows.Forms; using Microsoft.SqlServer.Management.Common; using Microsoft.SqlServer.Management.Smo;
添加以下代码
public void RestoreDatabase(String databaseName, String filePath, String serverName, String userName, String password, String dataFilePath, String logFilePath) { Restore sqlRestore = new Restore(); BackupDeviceItem deviceItem = new BackupDeviceItem (filePath, DeviceType.File); sqlRestore.Devices.Add(deviceItem); sqlRestore.Database = databaseName; ServerConnection connection; // for Windows Authentication if(userName == "") { SqlConnection sqlCon = new SqlConnection (@"Data Source="+serverName+@"; Integrated Security=True;"); connection = new ServerConnection(sqlCon); } // for Server Authentication else connection = new ServerConnection(serverName, userName, password); Server sqlServer = new Server(connection); Database db = sqlServer.Databases[databaseName]; sqlRestore.Action = RestoreActionType.Database; String dataFileLocation = dataFilePath + databaseName + ".mdf"; String logFileLocation = logFilePath + databaseName + "_Log.ldf"; db = sqlServer.Databases[databaseName]; RelocateFile rf = new RelocateFile(databaseName, dataFileLocation); sqlRestore.RelocateFiles.Add(new RelocateFile (databaseName, dataFileLocation)); sqlRestore.RelocateFiles.Add(new RelocateFile (databaseName + "_log", logFileLocation)); sqlRestore.ReplaceDatabase = true; sqlRestore.Complete += new ServerMessageEventHandler(sqlRestore_Complete); sqlRestore.PercentCompleteNotification = 10; sqlRestore.PercentComplete += new PercentCompleteEventHandler (sqlRestore_PercentComplete); try { sqlRestore.SqlRestore(sqlServer); } catch (Exception ex) { MessageBox.Show(ex.InnerException.ToString()); } db = sqlServer.Databases[databaseName]; db.SetOnline(); sqlServer.Refresh(); }
函数
RestoreDatabase
是一个打开与SQL Server的连接并从备份中还原数据库的函数。函数获取以下参数
databaseName
– 将执行还原操作的数据库名称filePath
– 文件路径serverName
– 服务器名称userName
– 用户名password
– 用户密码dataFilePath
– 数据库文件将具有的路径logFilePath
– 日志文件将具有的路径
如果需要Windows身份验证而不是用户名,则应输入一个空行,在这种情况下将忽略密码。
为
Commit
函数添加以下代码public override void Commit(System.Collections.IDictionary savedState) { // The code below changes the TARGETDIR permission // for a Windows Services running under the // NT AUTHORITY\NETWORK SERVICE account. try { DirectorySecurity dirSec = Directory.GetAccessControl (Context.Parameters["TargetDir"]); FileSystemAccessRule fsar = new FileSystemAccessRule (@"NT AUTHORITY\NETWORK SERVICE" , FileSystemRights.FullControl , InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit , PropagationFlags.None , AccessControlType.Allow); dirSec.AddAccessRule(fsar); Directory.SetAccessControl(Context.Parameters["TargetDir"], dirSec); } catch (Exception ex) { MessageBox.Show(ex.Message); } RestoreDatabase(Context.Parameters["databaseName"].ToString(), Context.Parameters["filePath"].ToString(),Context.Parameters ["serverName"].ToString(),Context.Parameters["userName"].ToString(), Context.Parameters["password"].ToString(), Context.Parameters ["dataFilePath"].ToString(), Context.Parameters["logFilePath"].ToString()); base.Commit(savedState); }
此函数代码确定对目录设置(“TargetDir”)和所有附加文件夹的完全访问权限,授予用户组
“NT AUTHORITY\NETWORK SERVICE”
。这将允许SQL Server为我们的数据库运行还原。如果数据库解压缩过程中“NT AUTHORITY\NETWORK SERVICE”
的访问被拒绝,则SqlRestore
函数会引发以下异常Restored failed for server '.\sqlexpress' (Microsoft.SqlServer.Express.Smo) Additional Information: System.Data.SqlClient.SqlError: The operating system returned the error '5 (Access is denied)' while attempting 'RestoreContainer::ValidateTargetForCreation' on '
\SampleDatabase_Log.ldf' (Microsoft.SqlServer.Expres.Smo) - 生成
SampleInstallLib
。
- 开始创建安装项目。
- 在
SampleInstallApp
中,执行File -> Add -> New Project
选择Other Projects -> Setup and Deployment,使用Setup Project模板。 - 设置应用程序名称为“
SampleInstall
”并单击OK。 - 在解决方案资源管理器中,选择新创建的项目,右键单击并选择“Properties”。在出现的窗口中单击“Prerequisites”。在“Prerequisites”窗口中,选择“Windows Installer 3.1”和“SQL Server 2005 Express Edition”的复选框,并固定“Download prerequisites from the same location as my application”选项。这将允许在安装包中启用Windows Installer和SQL Server。如果目标计算机上没有应用程序,它将安装它们,然后安装我们的应用程序。
- 在解决方案资源管理器中,单击“File system editor”。出现的文件夹显示目标计算机的文件系统。让我们复制我们的项目文件“SampleApplication”,库文件“SampleInstallLib.dll”,以及我们的数据库备份SampleDatabase.bak。必要的程序集将自动包含在我们的项目中。现在创建一个“Database”文件夹,我们的数据库文件将解压到其中。要创建文件夹,请右键单击“Application folder”并选择Add-> Folder,为其命名。在属性窗口中,选择
AlwaysCreate
为true
。 - 接下来创建项目输出。为此,选择Application Folder并右键单击选择Add-> Project Output。在“Add Project Output Group”窗口中,在“Project”中选择:
SampleInstallLib
,然后选择“Primary output”并单击OK。创建的Primary output将出现在文件列表中。
- 然后按解决方案资源管理器中的按钮并打开“Custom Actions Editor”。对于所有四个操作,选择
SamplesInstallLib
(Active
)的Primary output。为此,右键单击所需的操作并选择Add Custom Action。结果,我们得到以下内容
我们最后一步是为
Commit
操作传递参数/参数列表。在安装阶段,变量IDictionary savedState
(Commit
函数)会在Commit
事件激活时接收传输的参数。public override void Commit(System.Collections.IDictionary savedState)
参数显示在
CustomActionData
属性中。参数传递语法为paramName=”value”
。对于我们的任务,该行是
/TargetDir="[TARGETDIR]\" /databaseName="SampleDatabase" /filePath="[TARGETDIR]SampleDatabase.bak" /serverName=".\SQLEXPRESS" /userName="" /password="" /dataFilePath="[TARGETDIR]Database\\" /logFilePath="[TARGETDIR]Database\\"
- 构建
SampleInstall
项目,现在我们可以执行安装了。在解决方案资源管理器中右键单击项目并选择“Install”。Windows Installer会将文件复制到指定文件夹。如果复制成功,将授予用户组“NT AUTHORITY\NETWORK SERVICE”对安装目录的完全访问权限,数据库将解压到Database目录。
- 在
参考文献
- http://www.devcity.net/Articles/339/1/article.aspx
- http://msdn.microsoft.com/en-us/library/d9k65z2d(VS.80).aspx
- https://codeproject.org.cn/KB/cs/SQL_Server_2005_Database.aspx
- http://msdn.microsoft.com/en-us/library/microsoft.sqlserver.management.smo.restore.aspx
PS
当您创建自己的安装包时,可以忽略步骤2,而是使用本文档附带的存档中的自定义操作。
历史
- 2008年10月15日:初次发布