C#教程之自己动手写映射第五节[封装添加]

摘要:
修改后的组件图如下:每个组件的依赖关系仍然相同,只是添加了一个额外的组件DBUtility。传入的对象对象的属性中存在值。

一、动机

  我们通常在做项目的时候一般用到的三层结构依赖关系如下:

orm

  实体作为数据的载体,传输于各个组件之间。当实体到达数据操作层时,我们会把他承载的具体数据解析出来,然后利用SqlHelper.cs[也存放在数据操作层的组件中]把数据插入到数据库中,具体代码如下:

 1 /*
 2  *
 3  * 创建人:李林峰
 4  * 
 5  * 时  间:2012-08-01
 6  *
 7  * 描  述:员工类
 8  *
 9  */
10 
11 using System;
12 using System.Data;
13 
14 namespace CSharp.DAL
15 {
16     public class A
17     {
18         public static void Add(Model.Employee employee)
19         {
20             string strSQL = string.Format(@"INSERT INTO [A]([Name],[Password],[Department],[Position]) VALUES('{0}' ,'{1}','{2}' ,'{3}')", employee.Name, employee.Password, employee.Department, employee.Position);
21             SqlHelper.ExecuteNonQuery(Constant.CONNSTRING, CommandType.Text, strSQL);
22         }
23     }
24     public class B
25     {
26         public static void Add(Model.Employee employee)
27         {
28             string strSQL = string.Format(@"INSERT INTO [B]([Name],[Password],[Department]) VALUES('{0}' ,'{1}','{2}' ,'{3}')", employee.Name, employee.Password, employee.Department,);
29             SqlHelper.ExecuteNonQuery(Constant.CONNSTRING, CommandType.Text, strSQL);
30         }
31     }
32     public class C
33     {
34         public static void Add(Model.Employee employee)
35         {
36             string strSQL = string.Format(@"INSERT INTO [C]([Name],[Password]) VALUES('{0}' ,'{1}','{2}')", employee.Name, employee.Password);
37             SqlHelper.ExecuteNonQuery(Constant.CONNSTRING, CommandType.Text, strSQL);
38         }
39     }
40 }

   如上所示,我们在每个类里如果要实现“添加”操作,都会有一个方法,并且方法体内重复着写着INSERT INTO.....,为了减少我们的工作量,我们对上面的代码进行这样的理解:

1  public static void Add("变化的实体")
2  {
3       string strSQL = string.Format(@"INSERT INTO "变化的列") VALUES("变化的值");
4       SqlHelper.ExecuteNonQuery(Constant.CONNSTRING, CommandType.Text, strSQL);
5   }

二、构想
  既然重复的代码这么多,我们能不能把"添加"封装成一个方法呢?想像中的伪代码如下:

1  public static bool Add(object "对象")
2 {
3         //搞定添加......
4         //返回结果......
5 }

三、实现
  我们要实现对"添加"方法的封装以便能够重用,首先我们要改一下我们使用中各个组的依赖关系,把Add方法与SqlHelper类从DAL组件中分离出来放到新的组件中接口类型为object,彻底去除与"具体类型"的依赖关系。修改后的组件图如下:

C#教程之自己动手写映射第五节[封装添加]第2张

  各组件依赖关系依旧,只不过多加了个组件DBUtility。代码如下:

 1 /*
 2  *
 3  * 创建人:李林峰
 4  * 
 5  * 时  间:2012-08-01
 6  * 
 7  * 描  述:员工数据操作层
 8  *
 9  */
10 
11 using System;
12 using System.Data;
13 using CSharp.DBUtility;
14 
15 namespace CSharp.DAL
16 {
17     public class A
18     {
19         public static bool Add(Model.A a)
20         {
21             return ORM.Add(a);
22         }
23     }
24     public class B
25     {
26         public static bool Add(Model.B b)
27         {
28             return ORM.Add(b);
29         }
30     }
31     public class C
32     {
33         public static bool Add(Model.C c)
34         {
35             return ORM.Add(c);
36         }
37     }
38 }
39 
40 
41 /*
42  *
43  * 创建人:李林峰
44  * 
45  * 时  间:2012-08-01
46  * 
47  * 描  述:orm中封装后的添加方法
48  *
49  */
50 
51 namespace CSharp.DBUtility
52 {
53     public class ORM
54     {
55         public static bool Add(object Model)
56         {
57             //搞定添加......
58             return true;
59         }
60     }
61 }

  如上所示,要实现我们的思想,所有的添加操作都必须在"搞定添加......"中实现。

  引入实体与数据库的映射关系的概念:在Add方法中我们传入的是"带有数据的具体类型的对象",而我们要实现的add(object)这个实体的数据就应该存储到数据库中了,是具体的数据库插入操作,也就是说我们得到了数据,但不知道往哪个表里插入数据和这些数据应该插入到哪些字段中。这时候我们可以有一种新的想法"新建立一个依赖"对我们需要的信息进行描述以辅助我们完成该功能,如下所图所示:

C#教程之自己动手写映射第五节[封装添加]第3张

  我们再回头看看插入时的SQL语句:

1 INSERT INTO tableName (Column1,Column2....) VALUES (value1,value2....)

  通过引入实体与数据库的映射关系,我们得到了得到了插入时拼接SQL的所有信息,(1)tableName 存在于Mapping中。(2)Column存在于Mapping中。(3)value存在于传入的object对象的属性中。(4)具体哪个实体属性的值应该插入到哪个字段存在于Mapping中,如:Password属性值应该存入varPassword字段中。

  注入映射关系:即然我们的底层DBUtility要应用到这种关系,那么我们必然要把这种关系动态的注入到我们的组件中,这里我提出两种思路:

  1. 我们可以修改Add的对外接口为Add(object model,object mapping),[此时mapping可以是类文件,但不限于类文件,大多数情况下是xml文件,也可以是是文本文件,只要我们能够得到这种关系就可以]。
  2. 可以依赖一定的文件命名规则,如:实体类的名称为Employee,存储着么的映射类的名称就必须为EmployeeMapping,在实现的内部我们用反射来得到EmployeeMapping类的实例,并调用其属性或方法得到关系。这样我们就不用像上面一样每次都加上mapping这个参数了。

  万事俱备只吹东风:前面墨迹了那么多,也不知道能让别人看明白不,反正我是明白了,哈哈,现在写写实现吧,有代码有真相。

orm

  项目结构如上所示:在DAL里有4个类,Constant是获取Web.config的类,Employee与SqlHelper是我们最初写三层的写法示例,EmployeeORM是我们封装了底层后的新写法,DBUtility是我们新建立的组件,组件的对外接口为ORM类,其他类为辅助类。由于代比较多,这里只贴出DAL中的EmployeeORM类代码与ORM类的代码,其他的实现请自己下载调试吧。

 1 /*
 2  *
 3  * 创建人:李林峰
 4  * 
 5  * 时  间:2012-08-01
 6  * 
 7  * 描  述:员工数据操作层
 8  *
 9  */
10 
11 using System;
12 using System.Data;
13 using CSharp.DBUtility;
14 
15 namespace CSharp.DAL
16 {
17     public class EmployeeORM
18     {
19         public static bool Add(Model.Employee employee)
20         {
21             return ORM.Add(employee, Constant.ASSEMBLYPATH, Constant.CONNSTRING);
22         }
23     }
24 }
25 
26 
27 
28 /*
29  *
30  * 创建人:李林峰
31  * 
32  * 时  间:2010-08-01
33  *
34  * 描  述:对象关系映射类
35  *
36  */
37 
38 using System;
39 using System.Collections.Generic;
40 using System.Reflection;
41 
42 namespace CSharp.DBUtility
43 {
44     public class ORM
45     {
46         /// <summary>
47         /// 添加一个实体
48         /// </summary>
49         /// <param name="classObject"></param>
50         /// <returns></returns>
51         public static bool Add(object classObject, string AssemblyName, string ConnString)
52         {
53             int intMaxID = 0, intFlag = 0;
54             return Add(classObject, out intMaxID, intFlag, AssemblyName, ConnString);
55         }
56 
57         /// <summary>
58         /// 添加一个实体并且返回其ID标识
59         /// </summary>
60         /// <param name="classObject"></param>
61         /// <param name="intMaxID"></param>
62         /// <returns></returns>
63         public static bool Add(object classObject, out int intMaxID, string AssemblyName, string ConnString)
64         {
65             intMaxID = 0;
66             int intFlag = 1;
67             return Add(classObject, out intMaxID, intFlag, AssemblyName, ConnString);
68         }
69 
70         /// <summary>
71         /// 添加实体并判断是否返回最大的编号
72         /// </summary>
73         /// <param name="classObject"></param>
74         /// <param name="intMaxID"></param>
75         /// <param name="intFlag">当intFlag=0时,则不去取intMaxID,等于1则相反</param>
76         /// <returns></returns>
77         private static bool Add(object classObject, out int intMaxID, int intFlag, string AssemblyName, string ConnString)
78         {
79             //声名输出参数
80             intMaxID = 0;
81 
82             //获取表名称
83             string strTableName = Mapping.GetTableName(classObject, AssemblyName);
84             //获取主键字典
85             Dictionary<string, string> IdentityMapping = Mapping.GetIdentityMapping(classObject, AssemblyName);
86             //获取除主键以外的字段字典
87             Dictionary<string, string> BaseFieldMapping = Mapping.GetBaseFieldMapping(classObject, AssemblyName);
88             //获取 "属性--值" 字典
89             Dictionary<string, string> FieldValueMapping = Model.GetValueMapping(classObject, BaseFieldMapping);
90 
91             //创建SQL语句
92             string strSQL = SQL.CreateInsert(classObject, strTableName, IdentityMapping, BaseFieldMapping, FieldValueMapping, intFlag);
93 
94             //执行SQL
95             return SQL.ExecInsert(strSQL, out intMaxID, intFlag, ConnString);
96         }
97     }
98 }

四、总结

  这节内容引入了对象与数据库的映射的思想,这个思想在很多框架中都有应用,我们在平时开发过程中,不光要懂得怎么调用API实现功能,同时了解开发者的意图也是非常必要的,当你理解后你会发现,我们在"思想上还是很有潜力滴"。

五、源码下载
  06CSharp映射教程_05.rar

六、版权

  转载请注明出处:http://www.cnblogs.com/iamlilinfeng

七、工作类了,乐喝乐喝

  今天8月1号,上午一同事果断发图,老着笑了。。。

orm

免责声明:文章转载自《C#教程之自己动手写映射第五节[封装添加]》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇JSDOM获取子节点的一些方法版本控制 团队开发 svn服务器架设以及客户端svn配置下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Java中Map用法详解

原文地址http://blog.csdn.net/guomutian911/article/details/45771621 原文地址http://blog.csdn.net/sunny243788557/article/details/52806724 Map以按键/数值对的形式存储数据,这里要特别说明(Map.Entry,是Map的内部类,它用来描述M...

78.Java集合之Map

Map 如果程序中存储了几百万个学生,而且经常需要使用学号来搜索某个学生,那么这个需求有效的数据结构就是Map。Map是一种依照键(key)存储元素的容器,键(key)很像下标,在List中下标是整数。在Map中键(key)可以使任意类型的对象。Map中不能有重复的键(Key),每个键(key)都有一个对应的值(value)。一个键(key)和它对应的值构...

谈jdbcTemplate与mybatis

为什么会产生 Hibernate Mybatis 这类的dao层框架 传统的jdbc 虽然执行速度很快,但是开发效率很低,随着面向对象开发的设计思想,在面向对象编程中 将对象 进行持久化,存入关系型的数据库时,由于关系型数据库的设计思想是数学思维,在持久化时,必须要对象拆分各个属性值,才可存入数据库;传统的jdbc 持久化时 对象持久化时 ,取出对象的一个...

读取并监控文件的变化

读取并监控文件的变化 ASP.NET Core 具有很多针对文件读取的应用。比如我们倾向于采用JSON文件来定义配置,所以应用就会涉及针对配置文件读取。如果用户发送一个针对物理文件的HTTP请求,应用会根据指定的路径读取目标文件的内容并对请求予以响应。在一个ASP.NET Core MVC应用中,针对View的动态编译会涉及到根据预定义的路径映射关系来读取...

Mybatis

JDBCJDBC相关概念 JAVA程序都是通过JDBC连接数据库的,通过SQL对数据库编程,JDBC是由SUN公司提出的一些列规范,只定义了接口规范,具体实现由各个数据库厂商去实现,它是一种典型的桥接模式。 桥接模式是一种结构型设计模式,它的主要特点是把抽象与行为实现分离开来,分别定义接口,可以保持各部分的独立性以及应对他们的功能扩展。 JDBC规范...

FFmpeg流媒体处理-收流与推流

本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/10623968.html 1. 简介 流媒体是使用了流式传输的多媒体应用技术。如下是维基百科关于流媒体概念的定义: 流媒体 (streaming media) 是指将一连串的媒体数据压缩后,经过网络分段发送数据,在网络上即时传输影音以供观赏的一种技...