簡單實體框架
今天要說的實體框架並不是ADO.NET EntityFramework,而是利用特性與反射技術自己來搭建一個簡單的實體框架。在來講之前先說些題外話,我們知道要想使一個專案有更好的健壯性、可移植型,是要將專案分層,不管是c/s,還是b/s框架一般都是三層架構,資料處理層(DAL)、業務邏輯層(BLL)、介面顯示層(USL或者UI)。當然根據專案的業務流程可能分個七八層也是常有的事。今天主要講的是在資料處理層是怎樣實現實體架構的。
言歸正傳,現在開始構建框架,首先建立資料庫,就做一個學生選課資訊系統(StudentManage),包括三張表,一個學生資訊表(Students),一個課程表(CourseS),一個選課表(SCs),它們之間的關係如下圖所示:
好了,資料庫建好後,我們到程式中去進行操作,新建一個winform專案
看一下需要建立的類:
先來構建特性類
1 /// <summary>
2
3 /// 表特性類
4
5 /// </summary>
6
7 [AttributeUsage(AttributeTargets.Class)]//可以對類應用特性
8
9 public class TableAttribute:Attribute
10
11 {
12
13 /// <summary>
14
15 /// 表名16
17 /// </summary>
18
19 public string TableName
20
21 {
22
23 get;
24
25 set;
26
27 }
28
29 }
30
31 [AttributeUsage(AttributeTargets.Property)]//可以對屬性應用特性
32
33 public class FieldAttribute : Attribute
34
35 {
36
37 /// <summary>38
39 /// 欄位名
40
41 /// </summary>
42
43 public string FieldName
44
45 {
46
47 get;
48
49 set;
50
51 }
52
53 /// <summary>
54
55 /// 欄位型別
56
57 /// </summary>
58
59 public SqlDbType FieldType
60
61 {
62
63 get;
64
65 set;
66
67 }
68
69 /// <summary>
70
71 /// 是不是主鍵
72
73 /// </summary>
74
75 public bool IsPrimaryKey
76
77 {
78
79 get;
80
81 set;
82
83 }
84
85 /// <summary>
86
87 /// 是否為空
88
89 /// </summary>
90
91 public bool IsNull
92
93 {
94
95 get;
96
97 set;
98
99 }
100
101 /// <summary>
102
103 /// 是否是自動增長
104
105 /// </summary>
106
107 public bool IsIdentity
108
109 {
110
111 get;
112
113 set;
114
115 }
116
117 }
118
119 在構建實體類(和表是對應著的):
120
121 /// <summary>
122
123 /// 空介面,實體類的父類
124
125 /// </summary>
126
127 public class IEntity
128
129 {
130
131 }
132
133 //學生類
134
135 [Table(TableName = "Students")]//表名(注意TableAttribute可以簡寫為Table)
136
137 public class Student:IEntity
138
139 {
140
141 [Field(FieldName="StudentID",FieldType=SqlDbType.NVarChar,IsPrimaryKey=true)]//欄位特性
142
143 public string StudentID
144
145 {
146
147 get;
148
149 set;
150
151 }
152
153 [Field(FieldName="StudentName",FieldType=SqlDbType.NVarChar)]
154
155 public string StudentName
156
157 {
158
159 get;
160
161 set;
162
163 }
164
165 [Field(FieldName="Sex",FieldType=SqlDbType.NVarChar)]
166
167 public string Sex
168
169 {
170
171 get;
172
173 set;
174
175 }
176
177 [Field(FieldName="Age",FieldType=SqlDbType.TinyInt)]
178
179 public int Age
180
181 {
182
183 get;
184
185 set;
186
187 }
188
189 //課程類
190
191 [Table(TableName="Courses")]
192
193 public class Course:IEntity
194
195 {
196
197 [Field(FieldName="CourseID",FieldType=SqlDbType.Int,IsPrimaryKey=true,IsIdentity=true)]
198
199 public int CourseID
200
201 {
202
203 get;
204
205 set;
206
207 }
208
209 [Field(FieldName = "CourseName", FieldType = SqlDbType.NVarChar)]
210
211 public string CourseName
212
213 {
214
215 get;
216
217 set;
218
219 }
220
221 }
222
223 //選課實體類
224
225 [Table(TableName="SCs")]
226
227 public class SC:IEntity
228
229 {
230
231 [Field(FieldName="StudentID",FieldType=SqlDbType.NVarChar,IsPrimaryKey=true)]
232
233 public string StudentID
234
235 {
236
237 get;
238
239 set;
240
241 }
242
243 [Field(FieldName = "CourseID", FieldType = SqlDbType.Int, IsPrimaryKey = true)]
244
245 public int CourseID
246
247 {
248
249 get;
250
251 set;
252
253 }
254
255 }
好了,實體類構建完成後,我們就來構建實體操作類:
1 public class EntityOPT
2
3 {
4
5 string constr;//連線字串
6
7 SqlConnection con;//資料庫連線
8
9 /// <summary>
10
11 /// 資料初始化
12
13 /// </summary>
14
15 public EntityOPT()
16
17 {
18
19 constr = "server=.;database=StudentManage;uid=sa;pwd=sa"; ;
20
21 con = new SqlConnection(constr);
22
23 }
24
25 /// <summary>
26
27 /// 獲得表名
28
29 /// </summary>
30
31 /// <param name="type"></param>
32
33 /// <returns></returns>
34
35 string GetTableName(Type type)
36
37 {
38
39 return ((TableAttribute)type.GetCustomAttributes(true)[0]).TableName;//給類只加了一個自定義特性
40
41 }
42
43 public List<T> QueryAll<T>() where T : IEntity//由於不知道前臺會傳哪個實體類,所以用泛型
44
45 {
46
47 try
48
49 {
50
51 Type type = typeof(T);//得到型別
52
53 List<T> entitys = new List<T>();//實體集合
54
55 string sql = "select *from " + GetTableName(type);//獲得表名,拼接sql語句
56
57 SqlDataAdapter da = new SqlDataAdapter(sql, constr);
58
59 DataTable dt = new DataTable();
60
61 da.Fill(dt);//向DataTable中填充資料
62
63 foreach (DataRow row in dt.Rows)//遍歷所有行
64
65 {
66
67 ConstructorInfo conInfo = type.GetConstructor(new Type[0]);//得到建構函式
68
69 object obj = conInfo.Invoke(null);//例項化物件
70
71 foreach (PropertyInfo pi in type.GetProperties())//得到所有屬性
72
73 {
74
75 foreach (object ob in pi.GetCustomAttributes(true))//遍歷欄位所有特性
76
77 {
78
79 if (ob is FieldAttribute)
80
81 {
82
83 string fieldname = (ob as FieldAttribute).FieldName;//得到表中欄位的名字
84
85 pi.SetValue(obj, row[fieldname], null);//給實體類屬性賦值
86
87 break;
88
89 }
90
91 }
92
93 }
94
95 entitys.Add((T)obj);
96
97 }
98
99 return entitys;
100
101 }
102
103 catch (Exception ex)
104
105 {
106
107 throw new Exception("資料層查詢所有資料發生異常:" + ex.Message);
108
109 }
110
111 }
112
113 /// <summary>
114
115 /// 插入資料
116
117 /// </summary>
118
119 /// <param name="entity"></param>
120
121 /// <returns></returns>
122
123 public bool InsertEntity(IEntity entity)
124
125 {
126
127 try
128
129 {
130
131 Type type = entity.GetType();
132
133 List<SqlParameter> pars = new List<SqlParameter>();//sql引數集合
134
135 string sql = "insert into " + GetTableName(type) + " values(";
136
137 foreach (PropertyInfo pi in type.GetProperties())//遍歷類的所有屬性
138
139 {
140
141 foreach (object obj in pi.GetCustomAttributes(true))//遍歷屬性的特性
142
143 {
144
145
146
147 if (obj is FieldAttribute && !(obj as FieldAttribute).IsIdentity)//有些主鍵是不自動增長的,如學號
148
149 {
150
151 string par = "@" + (obj as FieldAttribute).FieldName;
152
153 sql += par + ",";//拼接sql語句
154
155 SqlParameter sp = new SqlParameter(par, (obj as FieldAttribute).FieldType);
156
157 sp.Value = pi.GetValue(entity, null);
158
159 pars.Add(sp);
160
161 break;
162
163 }
164
165 }
166
167 }
168
169 sql = sql.TrimEnd(',') + ")";//去掉多餘的逗號
170
171 return SaveChange(sql, pars);
172
173 }
174
175 catch (Exception ex)
176
177 {
178
179 throw new Exception(ex.Message);
180
181 }
182
183 }
184
185 /// <summary>
186
187 /// 刪除資料
188
189 /// </summary>
190
191 /// <param name="entity"></param>
192
193 /// <returns></returns>
194
195 public bool DeleteEntity(IEntity entity)
196
197 {
198
199 try
200
201 {
202
203 Type type = entity.GetType();
204
205 List<SqlParameter> sps = new List<SqlParameter>();
206
207 string sql = "delete " + GetTableName(type) + " where ";
208
209 foreach (PropertyInfo pi in type.GetProperties())
210
211 {
212
213 foreach (object obj in pi.GetCustomAttributes(true))
214
215 {
216
217 if (obj is FieldAttribute && (obj as FieldAttribute).IsPrimaryKey)
218
219 {
220
221 FieldAttribute fa = obj as FieldAttribute;
222
223 sql += fa.FieldName + "=@" + fa.FieldName+" and ";//可能會是聯合主鍵
224
225 SqlParameter sp = new SqlParameter("@" + fa.FieldName, fa.FieldType);
226
227 sp.Value = pi.GetValue(entity, null);
228
229 sps.Add(sp);
230
231 break;
232
233 }
234
235 }
236
237 }
238
239 sql = sql.Substring(0, sql.Length - 4);
240
241 return SaveChange(sql,sps);
242
243 }
244
245 catch (Exception ex)
246
247 {
248
249 throw new Exception(ex.Message);
250
251 }
252
253 }
254
255 /// <summary>
256
257 /// 更新資料
258
259 /// </summary>
260
261 /// <param name="entity"></param>
262
263 /// <returns></returns>
264
265 public bool UpdateEntity(IEntity entity)
266
267 {
268
269 try
270
271 {
272
273 Type type = entity.GetType();
274
275 List<SqlParameter> pars = new List<SqlParameter>();
276
277 string sql = "update " + GetTableName(type) + " set ";
278
279 string where = " where ";
280
281 foreach (PropertyInfo pi in type.GetProperties())
282
283 {
284
285 foreach (object obj in pi.GetCustomAttributes(true))
286
287 {
288
289 if (obj is FieldAttribute)
290
291 {
292
293 FieldAttribute fa = obj as FieldAttribute;
294
295 if (fa.IsPrimaryKey)
296
297 {
298
299
300
301 where += fa.FieldName + "=@" + fa.FieldName;
302
303 SqlParameter sp = new SqlParameter("@" + fa.FieldName, fa.FieldType);
304
305 sp.Value = pi.GetValue(entity, null);
306
307 pars.Add(sp);
308
309 }
310
311 else
312
313 {
314
315 sql += fa.FieldName + "=@" + fa.FieldName + ",";
316
317 SqlParameter sp = new SqlParameter("@" + fa.FieldName, fa.FieldType);
318
319 sp.Value = pi.GetValue(entity, null);
320
321 pars.Add(sp);
322
323 }
324
325 break;
326
327 }
328
329 }
330
331 }
332
333 sql = sql.TrimEnd(',') + where;
334
335 return SaveChange(sql, pars);
336
337 }
338
339 catch (Exception ex)
340
341 {
342
343 throw new Exception(ex.Message);
344
345 }
346
347 }
348
349 /// <summary>
350
351 /// 向資料庫提交資料
352
353 /// </summary>
354
355 /// <param name="sql"></param>
356
357 /// <param name="pars"></param>
358
359 /// <returns></returns>
360
361 bool SaveChange(string sql, List<SqlParameter> pars)
362
363 {
364
365 try
366
367 {
368
369 SqlCommand cmd = new SqlCommand(sql, con);
370
371 foreach (SqlParameter par in pars)
372
373 {
374
375 cmd.Parameters.Add(par);
376
377 }
378
379 con.Open();
380
381 int count = cmd.ExecuteNonQuery();
382
383 if (count > 0)
384
385 {
386
387 return true;
388
389 }
390
391 else
392
393 {
394
395 return false;
396
397 }
398
399 }
400
401 catch (Exception ex)
402
403 {
404
405
406
407 throw new Exception(ex.Message);
408
409 }
410
411 finally
412
413 {
414
415 con.Close();
416
417 }
418
419 }
420
421
422
423 }
好了,到這一步,一個簡單的實體框架算是構建完成,下面來測試。
先做一個介面:
四個button控制元件,一個dataGridView控制元件。
1 //先來做學生的新增:
2
3 Student student = new Student();
4
5 student.StudentID = "09040401036";
6
7 student.StudentName = "張三";
8
9 student.Age = 18;
10
11 student.Sex = "男";
12
13 if (entityopt.InsertEntity(student))
14
15 {
16
17 MessageBox.Show("新增成功!");
18
19 }
20
21 else
22
23 {
24
25 MessageBox.Show("新增失敗!");
26
27 }
28
29 //查詢操作:
30
31 private void button4_Click(object sender, EventArgs e)
32
33 {
34
35 dataGridView1.DataSource = entityopt.QueryAll<Student>();
36
37 }
單擊新增並查詢:
新增成功。
來做修改,把名字改為李四:
1 Student student = new Student();
2
3 student.StudentID = "09040401036";
4
5 student.StudentName = "李四";
6
7 student.Age = 18;
8
9 student.Sex = "男";
10
11 if (entityopt.UpdateEntity(student))
12
13 {
14
15 MessageBox.Show("修改成功!");
16
17 }
18
19 else
20
21 {
22
23 MessageBox.Show("修改失敗!");
24
25 }
單擊修改,並查詢:
修改成功。
刪除剛才的學生資訊:
1 Student student = new Student();
2
3 student.StudentID = "09040401036";
4
5 if (entityopt.DeleteEntity(student))
6
7 {
8
9 MessageBox.Show("刪除成功!");
10
11 }
12
13 else
14
15 {
16
17 MessageBox.Show("刪除失敗!");
18
19 }
刪除並查詢:
刪除成功。
下面在對課程操作,首先新增課程:
1 Course course = new Course();
2
3 course.CourseName = "C#";
4
5 if (entityopt.InsertEntity(course))
6
7 {
8
9 MessageBox.Show("新增成功!");
10
11 }
12
13 else
14
15 {
16
17 MessageBox.Show("新增失敗!");
18
19 }
20
21 //查詢操作:
22
23 dataGridView1.DataSource = entityopt.QueryAll<Course>();
點選新增,然後查詢,結果:
我們看到課程也新增成功了,在做修改:
1 Course course = new Course();
2
3 course.CourseID = 1;
4
5 course.CourseName = "asp.net";
6
7 if (entityopt.UpdateEntity(course))
8
9 {
10
11 MessageBox.Show("修改成功!");
12
13 }
14
15 else
16
17 {
18
19 MessageBox.Show("修改失敗!");
20
21 }
點選修改,並查詢,結果:
課程也能修改成功!
再來刪除!
1 Course course = new Course();
2
3 course.CourseID = 1;
4
5 if (entityopt.DeleteEntity(course))
6
7 {
8
9 MessageBox.Show("刪除成功!");
10
11 }
12
13 else
14
15 {
16
17 MessageBox.Show("刪除失敗!");
18
19 }
看一下執行結果:
刪除成功!
好了,到這一步我們發現實體框架構建成功,並能執行。不過注意了,如果要是做選課的修改時,不能直接呼叫修改方法,因為它是聯合主鍵,應該先刪除在新增,其實修改本本身就是先刪除後新增的過程。
好,今天講的東西雖然是簡單實體框架,但也有難度,一般大公司都有自己的實體框架,有不懂的地方可以和我交流。
https://www.cnblogs.com/yunfeiyang/archive/2011/06/11/2078533.html