.NET 制作有DB安装功能的安装文件

来源:岁月联盟 编辑:zhu 时间:2009-01-14

  前段时间做一个项目,因为其中数据库有许多数据是初始化的数据, 为了便于部署.于是我在制作安装程序的时候加入了 DB install的功能.

  首先最好单独创建一个DB install 的Class Library的Project.

  Fileà NewàProjectàVisual C# à WindowsàClass Library

  然后创建一个class, 命名为DBInstall.cs. 下面就是如何在这个class 中实现DB"安装"的过程.

  首先需要将 DBInstall 继承 Installer class. 还需要加上[RunInstaller(true)]的attribute.

  继承

1[RunInstaller(true)]
2
3public partial class DBInstall : Installer
4

  此时图标会由变为, 说明这个class 已经成为了安装的组件了.

  然后就是 override Rollback, Uninstall, Install 三个方法:

  Override Install Method

 1    public override void Rollback(System.Collections.IDictionary savedState)
 2
 3    {
 4
 5      base.Rollback(savedState);
 6
 7    
 8
 9      if (MessageBox.Show("Do you want to remove exist databases during rollback?", "Confirm", MessageBoxButtons.YesNo)
10
11        == DialogResult.Yes)
12
13      {
14
15        string dbname = "XXX"; //XXX 代表数据库名称
16
17        try
18
19        {
20
21          ExecuteSql("master", string.Format("DROP DATABASE [{0}]", dbname));   //回滚的时候删除数据库文件
22
23        }
24
25        catch
26
27        {
28
29          MessageBox.Show(string.Format("Can not delete [{0}] database. Please delete it by yourself."), dbname);
30
31        }
32
33       
34
35      }
36
37    }
38
39
40
41    public override void Uninstall(System.Collections.IDictionary savedState)
42
43    {
44
45      base.Uninstall(savedState);
46
47
48
49      try
50
51      {
52
53        if (MessageBox.Show("Do you want to remove databases?", "Confirm", MessageBoxButtons.YesNo)
54
55          == DialogResult.Yes)
56
57        {
58
59          DBConfig dbConfig = new DBConfig();               //自定义的一个界面,便于输入DB的信息
60
61          dbConfig.ShowDialog();                     //安装过程中显示自定义的数据DB安装信息的节目
62
63               
64
65          if (this.Context.Parameters.ContainsKey("dbsource")) //用自定义的界面输入的信息赋值给Context.Parameter,它主要负责记录install和uninstall过程中的参数
66
67          {
68
69            this.Context.Parameters["dbsource"] = DBConfig.IP;    
70
71          }
72
73          else
74
75          {
76
77            this.Context.Parameters.Add("dbsource", DBConfig.IP);
78
79          }
80
81          if (this.Context.Parameters.ContainsKey("user"))  //用自定义的界面输入的信息赋值给Context.Parameter,它主要负责记录install和uninstall过程中的参数  
82
83          {
84
85            this.Context.Parameters["user"] = DBConfig.DBUser;
86
87          }
88
89          else
90
91          {
92
93            this.Context.Parameters.Add("user", DBConfig.DBUser);
94
95          }
96
97          if (this.Context.Parameters.ContainsKey("pwd"))  //用自定义的界面输入的信息赋值给Context.Parameter,它主要负责记录install和uninstall过程中的参数
98
99          {
100
101            this.Context.Parameters["pwd"] = DBConfig.DBPwd;
102
103          }
104
105          else
106
107          {
108
109            this.Context.Parameters.Add("pwd", DBConfig.DBPwd);
110
111          }
112
113          string dbname = "XXX";                 // 数据库的名称
114
115          try
116
117          {
118
119            ExecuteSql("master", string.Format("DROP DATABASE [{0}]", dbname));
120
121          }
122
123          catch
124
125          {
126
127            MessageBox.Show(string.Format("Can not delete [{0}] database. Please delete it by your self."), dbname);
128
129          }         
130
131        }                  
132
133      }
134
135      catch (Exception ex)
136
137      {
138
139        MessageBox.Show("Can not delete some databases, please delete them manually.");
140
141      }
142
143    }
144
145
146
147    public override void Install(System.Collections.IDictionary stateSaver)
148
149    {
150
151      base.Install(stateSaver);
152
153
154
155      if (MessageBox.Show("Do you want to install databases?", "Confirm", MessageBoxButtons.YesNo)
156
157        == DialogResult.Yes)
158
159      {
160
161        DBConfig dbConfig = new DBConfig();
162
163        dbConfig.ShowDialog();
164
165        if (this.Context.Parameters.ContainsKey("dbsource"))
166
167        {
168
169          this.Context.Parameters["dbsource"] = DBConfig.IP;
170
171        }
172
173        else
174
175        {
176
177          this.Context.Parameters.Add("dbsource", DBConfig.IP);
178
179        }
180
181        if (this.Context.Parameters.ContainsKey("user"))
182
183        {
184
185          this.Context.Parameters["user"] = DBConfig.DBUser;
186
187        }
188
189        else
190
191        {
192
193          this.Context.Parameters.Add("user", DBConfig.DBUser);
194
195        }
196
197        if (this.Context.Parameters.ContainsKey("pwd"))
198
199        {
200
201          this.Context.Parameters["pwd"] = DBConfig.DBPwd;
202
203        }
204
205        else
206
207        {
208
209          this.Context.Parameters.Add("pwd", DBConfig.DBPwd);
210
211        }       
212
213        string dbname = "XXX";           // 数据库的名称
214
215        ExecuteSql("master", string.Format("CREATE DATABASE[{0}]", dbname)); //创建一个数据库
216
217        string sql = LoadSqlFromAssembly("SPRC.DB.sql");       //加载这个sql脚本
218
219        ExecuteSql(dbname, sql);             //运行生成数据的sql脚本.       
220
221      }
222
223    }
224

  上面描述了自定义安装的初步过程.

  Read Sql and Execute Sql

1   
2
3private string LoadSqlFromAssembly(string Name)
4
5    {
6
7      //得到当前程序集对象
8
9      Assembly Asm = Assembly.GetExecutingAssembly();
10
11      //创建sql脚本的流对象
12
13      Stream strm = Asm.GetManifestResourceStream(Asm.GetName().Name + "." + Name);
14
15      //读sql流对象
16
17      StreamReader reader = new StreamReader(strm);
18
19      return reader.ReadToEnd();
20
21    }
22
23
24
25    private void ExecuteSql(string DatabaseName, string Sql)
26
27    {
28
29      //创建一个数据库连接对象
30
31      this.conn = new SqlConnection();
32
33      this.conn.ConnectionString = "user id=" + this.Context.Parameters["user"]
34
35        + ";data source=" + this.Context.Parameters["dbsource"]
36
37        + ";initial catalog=master;password=" + this.Context.Parameters["pwd"] + ";";
38
39      //创建一个sql command对象,去运行sql脚本的内容
40
41      SqlCommand command = new SqlCommand(Sql, conn);
42
43      //open数据库的连接
44
45      command.Connection.Open();
46
47      //因为调用这个方法前,在install的方法里面command是运行在master的库上面的,所以需要change到当前数据库中.
48
49      command.Connection.ChangeDatabase(DatabaseName);
50
51      try
52
53      {
54
55        //执行sql脚本,生成数据表和初始数据.
56
57        command.ExecuteNonQuery();
58
59      }
60
61      finally
62
63      {
64
65        //Finally, blocks are a great way to ensure that the connection
66
67        //is always closed.
68
69        command.Connection.Close();
70
71      }
72
73
74
75    }
76

  下面描述下LoadSqlFromAssembly 和 ExecuteSql两个方法: 

  自此在上面DBInstall的Project已经全部实现完毕.还需要在安装部署中添加这个DBInstall.

  创建一个Setup Project(Fileà NewàProjectàOther Project Typeà Setup and DeploymentàSetup Project,然后再刚创建号的

  Setup project点击右键, 点击"添加", 选择Project Output,在Project 选择刚已经完成的DBInstall, 然后点击 Primary output.

  然后点击"确定". 

  然后再在Setup Project上面点击右键, 点击"View"à"Custom Actions",会弹出一个窗口

  然后在窗口中依次在Install, Rollback, Uninstall 三个文件夹上面创建 一个Action.

  方法如下:

  在文件夹上面点击右键,然后点击"Add Custom Action", 再弹出窗口里面选择Application Folder.

  选择刚才创建的一个DBInstall的Primary Output . 

  然后点击"确定".

  注意一定要在Install, Rollback, Uninstall 都添加 "Primary output from DBInstall(Active)".

  只有这样,我们在DBInstall中override的 Rollback, Uninstall才会有意义. 

  然后编译setup project, 得到安装文件,双击安装.   

  PS: 有时候大家生成的脚本在sql里面执行的正常, 但是在安装过程中会出现 "Create 附近有错误"类似的错误,

  请大家去掉sql文件里面的"GO". 就可以一切正常了.

  如果大家有更好的办法, 请多多指教! 谢谢!