介绍
这篇文章讨论如何在c#中实现3层架构,使用MS Access数据库存储数据。在此,我在3层架构中实现一个小型的可复用的组件保存客户数据。并提供添加,更新,查找客户数据的功能。
背景
首先,我介绍一些3层架构的理论知识。简单说明:什么是3层架构?3层架构的优点是什么?
什么是3层架构?
3层架构是一种“客户端-服务器”架构,在此架构中用户接口,商业逻辑,数据保存以及数据访问被设计为独立的模块。主要有3个层面,第一层(表现层,GUI层),第二层(商业对象,商业逻辑层),第三层(数据访问层)。这些层可以单独开发,单独测试。
为什么要把程序代码分为3层,把用户接口层,商业逻辑层,数据访问层分离有许多的优点。
在快速开发中重用商业逻辑组件,我们已经在系统中实现添加,更新,删除,查找客户数据的组件。这个组件已经开发并且测试通过,我们可以在其他要保存客户数据的项目中使用这个组件。
系统比较容易迁移,商业逻辑层与数据访问层是分离的,修改数据访问层不会影响到商业逻辑层。系统如果从用SQL Server存储数据迁移到用Oracle存储数据,并不需要修改商业逻辑层组件和GUI组件
系统容易修改,假如在商业层有一个小小的修改,我们不需要在用户的机器上重装整个系统。我们只需要更新商业逻辑组件就可以了。
应用程序开发人员可以并行,独立的开发单独的层。
代码
这个组件有3层,第一个层或者称为GUI层用form实现,叫做FrmGUI。第二层或者称为商业逻辑层,叫做BOCustomer,是Bussniess Object Customer的缩写。最后是第三层或者称为数据层,叫做DACustomer,是Data Access Customer的缩写。为了方便我把三个层编译到一个项目中。
用户接口层
下面是用户接口成的一段代码,我只选取了调用商业逻辑层的一部分代码。
1
//This function get the details from the user via GUI 2
//tier and calls the Add method of business logic layer.3
private void cmdAdd_Click(object sender, System.EventArgs e)4


{5
try6

{7

8
cus = new BOCustomer();9

10
cus.cusID=txtID.Text.ToString();11

12
cus.LName = txtLName.Text.ToString();13

14
cus.FName = txtFName.Text.ToString();15

16
cus.Tel= txtTel.Text.ToString();17

18
cus.Address = txtAddress.Text.ToString();19

20
cus.Add();21

22
}23

24
catch(Exception err)25

26

{27

28
MessageBox.Show(err.Message.ToString());29

30
}31

32
}33

34
35

36
//This function gets the ID from the user and finds the 37

38
//customer details and return the details in the form of39

40
//a dataset via busniss object layer. Then it loops through 41

42
//the content of the dataset and fills the controls.43

44
45

46
private void cmdFind_Click(object sender, System.EventArgs e)47

48


{49

50
try51

52

{53

54
String cusID = txtID.Text.ToString();55

56
57

58
BOCustomer thisCus = new BOCustomer();59

60
61

62
DataSet ds = thisCus.Find(cusID);63

64
65

66
DataRow row;67

68
row = ds.Tables[0].Rows[0];69

70
71

72
//via looping73

74
foreach(DataRow rows in ds.Tables[0].Rows )75

76

{77

78
txtFName.Text = rows["CUS_F_NAME"].ToString();79

80
txtLName.Text = rows["CUS_L_NAME"].ToString();81

82
txtAddress.Text = rows["CUS_ADDRESS"].ToString();83

84
txtTel.Text = rows["CUS_TEL"].ToString();85

86
}87

88
}89

90
catch (Exception err)91

92

{93

94
MessageBox.Show(err.Message.ToString());95

96
}97

98
99

100
}101

102
103

104
//this function used to update the customer details. 105

106
private void cmdUpdate_Click(object sender, 107

108
System.EventArgs e)109

110


{111

112
try113

114

{115

116
cus = new BOCustomer();117

118
cus.cusID=txtID.Text.ToString();119

120
cus.LName = txtLName.Text.ToString();121

122
cus.FName = txtFName.Text.ToString();123

124
cus.Tel= txtTel.Text.ToString();125

126
cus.Address = txtAddress.Text.ToString();127

128
129

130
cus.Update();131

132
}133

134
catch(Exception err)135

136

{137

138
MessageBox.Show(err.Message.ToString());139

140
}141

142
}143

144

商业逻辑层
下面是商业逻辑层的所有代码,主要包括定义customer对象的属性。但这仅仅是个虚构的customer对象,如果需要可以加入其他的属性。商业逻辑层还包括添加,更新,查找,等方法。
商业逻辑层是一个中间层,处于GUI层和数据访问层中间。他有一个指向数据访问层的引用cusData = new DACustomer().而且还引用了System.Data名字空间。商业逻辑层使用DataSet返回数据给GUI层。
1
using System;2

3
using System.Data;4

5
6

7
namespace _3tierarchitecture8

9


{10

11

/**//// <SUMMARY>12

13
/// Summary description for BOCustomer.14

15
/// </SUMMARY>16

17
18

19
public class BOCustomer20

21

{22

23
//Customer properties24

25
private String fName;26

27
private String lName;28

29
private String cusId;30

31
private String address;32

33
private String tel;34

35
36

37
private DACustomer cusData;38

39
40

41
public BOCustomer()42

43

{44

45
//An instance of the Data access layer!46

47
cusData = new DACustomer();48

49
} 50

51
52

53
54

55
56

57

/**//// <SUMMARY>58

59
/// Property FirstName (String)60

61
/// </SUMMARY>62

63
public String FName 64

65

{66

67
68

69
get70

71

{72

73
return this.fName;74

75
}76

77
set78

79

{80

81
try82

83

{84

85
this.fName = value;86

87
88

89
if (this.fName == "")90

91

{92

93
throw new Exception(94

95
"Please provide first name
");96

97
}98

99
}100

101
catch(Exception e)102

103

{104

105
throw new Exception(e.Message.ToString());106

107
}108

109
}110

111
}112

113
114

115

/**//// <SUMMARY>116

117
/// Property LastName (String)118

119
/// </SUMMARY>120

121
public String LName122

123

{124

125
get126

127

{128

129
return this.lName;130

131
}132

133
set134

135

{136

137
//could be more checkings here eg revmove ' chars138

139
//change to proper case140

141
//blah blah142

143
this.lName = value;144

145
if (this.LName == "")146

147

{148

149
throw new Exception("Please provide name
");150

151
}152

153
154

155
}156

157
}158

159
160

161

/**//// <SUMMARY>162

163
/// Property Customer ID (String)164

165
/// </SUMMARY>166

167
public String cusID168

169

{170

171
get172

173

{174

175
return this.cusId;176

177
}178

179
set180

181

{182

183
this.cusId = value;184

185
if (this.cusID == "")186

187

{188

189
throw new Exception("Please provide ID
");190

191
}192

193
194

195
}196

197
}198

199
200

201

/**//// <SUMMARY>202

203
/// Property Address (String)204

205
/// </SUMMARY>206

207
public String Address208

209

{210

211
get212

213

{214

215
return this.address;216

217
}218

219
set220

221

{222

223
this.address = value;224

225
226

227
if (this.Address == "")228

229

{230

231
throw new Exception("Please provide address
");232

233
}234

235
}236

237
}238

239
240

241

/**//// <SUMMARY>242

243
/// Property Telephone (String)244

245
/// </SUMMARY>246

247
public String Tel248

249

{250

251
get252

253

{254

255
return this.tel;256

257
}258

259
set260

261

{262

263
this.tel = value;264

265
if (this.Tel == "")266

267

{268

269
throw new Exception("Please provide Tel
");270

271
}272

273
274

275
}276

277
}278

279
280

281

/**//// <SUMMARY>282

283
/// Function Add new customer. Calls 284

285
/// the function in Data layer.286

287
/// </SUMMARY>288

289
public void Add()290

291

{292

293
cusData.Add(this);294

295
}296

297
298

299
300

301

/**//// <SUMMARY>302

303
/// Function Update customer details. 304

305
/// Calls the function in Data layer.306

307
/// </SUMMARY>308

309
public void Update() 310

311

{312

313
cusData.Update(this);314

315
}316

317
318

319

/**//// <SUMMARY>320

321
/// Function Find customer. Calls the 322

323
/// function in Data layer.324

325
/// It returns the details of the customer using 326

327
/// customer ID via a Dataset to GUI tier.328

329
/// </SUMMARY>330

331
public DataSet Find(String str) 332

333

{334

335
if (str == "")336

337
throw new Exception("Please provide ID to search");338

339
340

341
DataSet data = null;342

343
344

345
data = cusData.Find(str);346

347
348

349
return data;350

351
}352

353
}354

355
}356

357

数据访问层
数据层包括处理MS Access数据库的细节。所有这些细节都是透明的,不会影响到商业逻辑层。数据访问层有个指向商业逻辑层的引用BOCustomer cus。为了应用方便并且支持其他数据库。
1
using System;2

3
using System.Data.OleDb;4

5
using System.Data;6

7
8

9
namespace _3tierarchitecture10

11
12

13


{14

15
16

17

/**//// <SUMMARY>18

19
/// Summary description for DACustomer.20

21
/// </SUMMARY>22

23
public class DACustomer24

25

{26

27
private OleDbConnection cnn;28

29
//change connection string as per the 30

31
//folder you unzip the files32

33
private const string CnnStr = 34

35
"Provider=Microsoft.Jet.OLEDB.4.0;Data " +36

37
"Source= D:\\Rahman_Backup\\Programming\\" + 38

39
"Csharp\\3tierarchitecture\\customer.mdb;";40

41
42

43
//local variables44

45
private String strTable="";46

47
private String strFields="";48

49
private String strValues="";50

51
private String insertStr="";52

53
54

55
//this needs to be changed based on customer 56

57
//table fields' Name of the database!58

59
private const String thisTable = "tblCustomer";60

61
private const String cus_ID = "CUS_ID";62

63
private const String cus_LName = "CUS_L_NAME";64

65
private const String cus_FName = "CUS_F_NAME";66

67
private const String cus_Tel = "CUS_TEL";68

69
private const String cus_Address = "CUS_ADDRESS";70

71
72

73
74

75
public DACustomer()76

77

{78

79
}80

81
82

83
public DACustomer(BOCustomer cus)84

85

{86

87
// A reference of the business object class88

89
}90

91
92

93
//standard dataset function that adds a new customer94

95
96

97
public void Add(BOCustomer cus)98

99

{100

101
102

103
String str = BuildAddString(cus);104

105
106

107
OpenCnn();108

109
110

111
//Open command option - cnn parameter is imporant112

113
OleDbCommand cmd = new OleDbCommand(str,cnn);114

115
116

117
118

119
//execute connection120

121
cmd.ExecuteNonQuery();122

123
124

125
// close connection126

127
CloseCnn();128

129
130

131
}132

133
134

135
//standard dataset function that updates 136

137
//details of a customer based on ID138

139
public void Update(BOCustomer cus)140

141

{142

143
OpenCnn();144

145
146

147
String selectStr = "UPDATE " + thisTable + 148

149
" set " + cus_LName + " = '" + cus.LName + "'" +150

151
", " + cus_FName + " = '" + cus.FName + "'" +152

153
", " + cus_Address + " = '" + cus.Address + "'" +154

155
", " + cus_Tel + " = '" + cus.Tel + "'" +156

157
" where cus_ID = '" + cus.cusID + "'";158

159
160

161
OleDbCommand cmd = new OleDbCommand(selectStr,cnn);162

163
164

165
cmd.ExecuteNonQuery();166

167
168

169
CloseCnn();170

171
}172

173
174

175
//standard dataset function that finds and 176

177
//return the detail of a customer in a dataset178

179
public DataSet Find(String argStr)180

181

{182

183
DataSet ds=null;184

185
186

187
try188

189

{190

191
OpenCnn();192

193
194

195
String selectStr = "select * from " + thisTable + 196

197
" where cus_ID = '" + argStr + "'";198

199
OleDbDataAdapter da = 200

201
new OleDbDataAdapter(selectStr,cnn);202

203
ds = new DataSet();204

205
da.Fill(ds,thisTable);206

207
208

209
CloseCnn();210

211
212

213
214

215
}216

217
catch(Exception e)218

219

{220

221
String Str = e.Message;222

223
}224

225
226

227
return ds;228

229
}230

231
232

233
private void OpenCnn()234

235

{236

237
// initialise connection238

239
String cnnStr = CnnStr;240

241
cnn = new OleDbConnection(cnnStr);242

243
// open connection244

245
cnn.Open();246

247
}248

249
250

251
private void CloseCnn()252

253

{254

255
// 5- step five256

257
cnn.Close();258

259
}260

261
262

263
// just a supporting function that builds 264

265
// and return the insert string for dataset.266

267
private String BuildAddString(BOCustomer cus)268

269

{270

271
// these are the constants as 272

273
// set in the top of this module.274

275
strTable="Insert into " + thisTable;276

277
strFields=" (" + cus_ID + 278

279
"," + cus_LName + 280

281
"," + cus_FName + 282

283
"," + cus_Address + 284

285
"," + cus_Tel + ")";286

287
288

289
//these are the attributes of the 290

291
//customer business object.292

293
strValues= " Values ( '" + cus.cusID + 294

295
"' , '" + cus.LName + 296

297
"' , '" + cus.FName + 298

299
"' , '" + cus.Address + 300

301
"' , '" + cus.Tel + "' )";302

303
304

305
insertStr = strTable + strFields + strValues;306

307
308

309
return insertStr;310

311
312

313
}314

315
}316

317
}318

浙公网安备 33010602011771号