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


    一、动机

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

    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,彻底去除与"具体类型"的依赖关系。修改后的组件图如下:

      各组件依赖关系依旧,只不过多加了个组件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)这个实体的数据就应该存储到数据库中了,是具体的数据库插入操作,也就是说我们得到了数据,但不知道往哪个表里插入数据和这些数据应该插入到哪些字段中。这时候我们可以有一种新的想法"新建立一个依赖"对我们需要的信息进行描述以辅助我们完成该功能,如下所图所示:

      我们再回头看看插入时的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

  • 相关阅读:
    集合
    java正则表达式
    jvm系列(四):jvm知识点总结
    jvm系列(三):java GC算法 垃圾收集器
    Android IOS WebRTC 音视频开发总结(十六)-- 音频设备操作之opensl与jni
    Android IOS WebRTC 音视频开发总结(十五)-- 培训课程大纲
    Android IOS WebRTC 音视频开发总结(十四)-- sip和xmpp异同
    Android IOS WebRTC 音视频开发总结(十三)-- ice原理
    Android IOS WebRTC 音视频开发总结(十二)-- sufaceview
    Android IOS WebRTC 音视频开发总结(十一)-- stun&turn部署
  • 原文地址:https://www.cnblogs.com/iamlilinfeng/p/2612523.html
Copyright © 2020-2023  润新知