zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    SCILAB简介[z]
    UG OPEN API编程基础 2约定及编程初步
    Office 2003与Office 2010不能共存的解决方案
    UG OPEN API 编程基础 3用户界面接口
    NewtonRaphson method
    UG OPEN API编程基础 13MenuScript应用
    UG OPEN API编程基础 14API、UIStyler及MenuScript联合开发
    UG OPEN API编程基础 4部件文件的相关操作
    UG OPEN API编程基础 1概述
    16 UG Open的MFC应用
  • 原文地址:https://www.cnblogs.com/iamlilinfeng/p/2612523.html
Copyright © 2011-2022 走看看