提纲

一、什么是ORM。
二、反射以及Attribute在ORM中的应用。
三、创建一个数据库表和表对应的实体model。
四、实体model如何映射出数据库表。
五、组合ORM映射生成insert语句。
六、测试ORM的插入映射。
七、总结。

内容:

一 、什么是ORM?

概念: 对象关系映射(Object Relational Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换。

详细介绍:  让我们从O/R开始。字母O起源于"对象"(Object),而R则来自于"关系"(Relational)。几乎所有的程序里面,都存在对象和关系数据库。在业务逻辑层和用户界面层中,我们是面向对象的。当对象信息发生变化的时候,我们需要把对象的信息保存在关系数据库中。 
        当你开发一个应用程序的时候(不使用O/R Mapping),你可能会写不少数据访问层的代码,用来从数据库保存,删除,读取对象信息,等等。你在DAL中写了很多的方法来读取对象数据,改变状态对象等等任务。而这些代码写起来总是重复的。 
        ORM解决的主要问题是对象关系的映射。域模型和关系模型分别是建立在概念模型的基础上的。域模型是面向对象的,而关系模型是面向关系的。一般情况下,一个持久化类和一个表对应,类的每个实例对应表中的一条记录,类的每个属性对应表的每个字段。 
        ORM技术特点: 
        1.提高了开发效率。由于ORM可以自动对Entity对象与数据库中的Table进行字段与属性的映射,所以我们实际可能已经不需要一个专用的、庞大的数据访问层。 
        2.ORM提供了对数据库的映射,不用sql直接编码,能够像操作对象一样从数据库获取数据。

二、反射以及Attribute在ORM中的应用。

什么是反射?
简单点吧,反射就是在运行时动态获取对象信息的方法,比如运行时知道对象有哪些属性,方法,委托等等等等。
反射有什么用呢?
反射不但让你在运行是获取对象的信息,还提供运行时动态调用对象方法以及动态设置、获取属性等的能力。
反射在ORM中有什么用呢?
我 这里所讨论的ORM实现是通过自定义Attribute的方式进行映射规则的描述的。但是我们并不知道具体哪个对象需要对应哪个表,并且这些对象是独立于 我们的ORM框架的,所以我们只能通过自定义Attribute来定义映射规则,然后通过反射来动态获取这些映射规则。
(这里只简单说明下概念:具体如何实现过程请看第四项。)

三、创建一个数据库表和表对应的实体model。

     传统的创建表和model实体的创建过程。

    1.创建数据库表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
create table TB_People
(
     Pl_ID Int identity(1,1) primary key ,      
 
    PL_Age Int,
 
    Pl_Sex Nvarchar(4),
 
     Pl_LoginName nvarchar(30),
 
     Pl_TrueName  nvarchar(30),
 
     PL_Pwd  nvarchar(60)
)

  2.根据表结构一般我们会创建如下model实体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace FuzhuKeji
{
    public class M_People
    {
 
        string _Pl_ID;
 
        public string Pl_ID
        {
            get return _Pl_ID; }
            set { _Pl_ID = value; }
        }
 
        int _PL_Age;
 
        public int PL_Age
        {
            get return _PL_Age; }
            set { _PL_Age = value; }
        }
 
        string _Pl_Sex;
 
        public string Pl_Sex
        {
            get return _Pl_Sex; }
            set { _Pl_Sex = value; }
        }
 
        string _Pl_LoginName;
 
        public string Pl_LoginName
        {
            get return _Pl_LoginName; }
            set { _Pl_LoginName = value; }
        }
 
        string _Pl_TrueName;
 
        public string Pl_TrueName
        {
            get return _Pl_TrueName; }
            set { _Pl_TrueName = value; }
        }
 
        string _PL_Pwd;
 
        public string PL_Pwd
        {
            get return _PL_Pwd; }
            set { _PL_Pwd = value; }
        }
 
    }
}

现在看到了表结构 和model实体,那如何根据model实体映射出表的插入语句及结构呢?下面我们就介绍有model映射到数据库表。

四、实体model如何映射出数据库表。

上面简单介绍了反射以及Attribute在ORM中的应用,那如何通过这些进行映射出来的呢?

方法一:

看到 题纲三中的model实体了,下面我们就通过反射的方法来动态获取此映射规则:

/// <summary>
/// 测试映射
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button1_Click(object sender, EventArgs e)
{
M_People mp = new M_People();
mp.PL_Age = 26;
mp.Pl_ID = "001";
mp.Pl_LoginName = "Test1";
mp.PL_Pwd = "123";
mp.Pl_Sex = "男";
mp.Pl_TrueName = "张三";
PropertyInfo[] infos = mp.GetType().GetProperties(); string Message_shuxing1 = ""; foreach (PropertyInfo info in infos)
{
//获取属性并打印
Message_shuxing1 = Message_shuxing1 + (info.Name + ":" + info.GetValue(mp, null));
} MessageBox.Show("这里看到可以获得属性名称和属性值(是不是对ORM有点慢慢明白了):"+Message_shuxing1); // 上面info.GetValue(mp, null)获得属性的值。
//info.SetValue(mp, "XX", null); 赋值 }

测试效果图如下:

是不是有点思路了,知道如何搞了,呵呵。

看到红色部分了吗

有感觉了没有:是不是和数据库的名称一样,而且还获得了值。为什么会出现这种情况呢?

属性是来至那?--Model实体吧,属性的名称也是model实体属性名称吧。所以我们只要把属性的名称按某个规则定义就可以获得其对应的数据库字段名和类型。

方法二:

备注下:其实不只这种方法可以完成ORM的映射,而且还可以通过Attribute:
Attribute中文翻译虽然也号称“属性”,但是她和对象的属性(Property)其实是完全不同的两概念。她是在运行时对对象或者对象属性、方法、委托等等进行描述的类,用于在运行时描述你的代码或者在运行时影响你的程序的行为。
其 实我们在c#的编程中经常看到Attribute,只不过我们没有注意罢了。比如Main函数前的“[STAThread]”这个其实就是一个 Attribute。全程为[STAThreadAttribute]。另外指定类可序列化的[Serializable]等等。是不是都很熟悉啊?只不 过平时估计没有用到,所以没有注意罢了。

既然Attribute是类,那么她的定义方法和类就没有两样了,唯一的不同就是自定义Attribute类必须继承于System.Attribute。

那我们改下M_People实体的东西如下:

下面我们来简单定义一个描述数据库字段信息的Attribute,在此类中我们采用更省略的方式,仅仅提供“字段名”,“字段类型”:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class DataFieldAttribute : Attribute
    {
        private string _FieldName;
        private string _FieldType;
        public DataFieldAttribute(string fieldname, string fieldtype)
        {
            this._FieldName = fieldname;
            this._FieldType = fieldtype;
        }
        public string FieldName
        {
            get return this._FieldName; }
            set this._FieldName = value; }
        }
        public string FieldType
        {
            get return this._FieldType; }
            set this._FieldType = value; }
        }
    }

那我们把Mode更改下改为如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
public class M_People
    {
 
        string _Pl_ID;
        [DataFieldAttribute("Pl_ID""Int")]
        public string Pl_ID
        {
            get return _Pl_ID; }
            set { _Pl_ID = value; }
        }
 
        int _PL_Age;
        [DataFieldAttribute("PL_Age""Int")]
        public int PL_Age
        {
            get return _PL_Age; }
            set { _PL_Age = value; }
        }
 
        string _Pl_Sex;
        [DataFieldAttribute("Pl_Sex""nvarchar")]
        public string Pl_Sex
        {
            get return _Pl_Sex; }
            set { _Pl_Sex = value; }
        }
 
        string _Pl_LoginName;
        [DataFieldAttribute("Pl_LoginName""nvarchar")]
        public string Pl_LoginName
        {
            get return _Pl_LoginName; }
            set { _Pl_LoginName = value; }
        }
 
        string _Pl_TrueName;
        [DataFieldAttribute("Pl_TrueName""nvarchar")]
        public string Pl_TrueName
        {
            get return _Pl_TrueName; }
            set { _Pl_TrueName = value; }
        }
 
        string _PL_Pwd;
        [DataFieldAttribute("PL_Pwd""nvarchar")]
        public string PL_Pwd
        {
            get return _PL_Pwd; }
            set { _PL_Pwd = value; }
        }
 
    }

通过自定义Attribute,我们定义了类属性和数据库字段的一一对应关系。

那我们通过事件测试下方法案例:

/// <summary>
/// 反射+Attribute 映射出数据库表
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button2_Click(object sender, EventArgs e)
{
M_People mp = new M_People();
mp.PL_Age = 26;
mp.Pl_ID = "001";
mp.Pl_LoginName = "Test1";
mp.PL_Pwd = "123";
mp.Pl_Sex = "男";
mp.Pl_TrueName = "张三"; PropertyInfo[] infos = mp.GetType().GetProperties();
string Str_TestAtrrubute = ""; object[] objDataFieldAttribute = null;
foreach (PropertyInfo info in infos)
{
objDataFieldAttribute = info.GetCustomAttributes(typeof(DataFieldAttribute), false);
if (objDataFieldAttribute != null)
{
Str_TestAtrrubute=Str_TestAtrrubute+(info.Name + "->数据库字段:" + ((DataFieldAttribute)objDataFieldAttribute[0]).FieldName)+" --------";
}
} MessageBox.Show(Str_TestAtrrubute);
}

测试的效果图如下:

哈 哈,你是不是很想动手了啊?

加油!下面我们就介绍如何实现插入语句的映射!

五、组合ORM映射生成insert语句。

我们仔细思考下看到上面的我们会怎么想才可以生成一条sql语句并且执行。

首先我们是不是应该分开两部分,

第一步负责生成插入语句。

第二步是负责执行插入语句得。

我们继续思考?生成一条插入语句我们要考虑哪些问题?

a、是不是返回值

b、是不是要判断表中是否有不需要组合为插入语句的字段(如自增字段)

c、而且这个插入语句是针对对象的插入语句而不是固定的某个或者已知的某个实体。所以我们会考虑到泛型的使用。

这样我们基本确定了insert语句的参数和结构。

我们再回到第一步如何根据实体生成插入语句? 我们第四部也只是说了根据实体映射出和数据库字段一样的名字,这有什么用呢?

肯定根据这些字段名我们要想办法组合个sql语句。继续分析、、、

如何分工 :肯定要给个执行的sql语句

分工一:是不是获得属性名称组合sql。

分工二:是不是做个参数的对应表。

分工三:组合这些东西,并把其属性类型和数据库字段类型对应起来。

上面说了那么多,只是帮大家打开思路,其实只要你理解了映射(第四项),用自己的思路去写那些组合sql也可以得,

我这个地方写的也不见得完美,只是给大家做个例子,嘿嘿,一起加油!

有几个地方用到了枚举首先我列出枚举的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
第一个属性标识是否为主键或者读写的标识
[Serializable]
  [Flags]
  public enum ColumnKeyType
  {
      /// <summary>
      /// 默认状态
      /// </summary>
      Default = 1,
 
      /// <summary>
      /// 标识为主键
      /// </summary>
      Identity = 2,
 
      /// <summary>
      /// Extend状态下,不参与读取、增加、修改
      /// </summary>
      Extend = 4,
 
      /// <summary>
      /// Read状态下不参与增加、修改
      /// </summary>
      Read = 8
  }
 
返回值做了枚举:
  public enum DBReturnType
  /// <summary>
      /// 返回受影响的行数
      /// </summary>
      EffectRow,
      /// <summary>
      /// 返回最后插入的主键值
      /// </summary>
      Identity
  }

插入语句的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#region 把对象内容保存到数据库中 Insert
      /// <summary>
      /// 把对象内容保存到数据库中
      /// </summary>
      /// <typeparam name="T"></typeparam>
      /// <param name="model"></param>
      /// <param name="isIncludeKeyColumn">插入语句中是否包含对主键的插入,当主键值为自动增加时为false</param>
      /// <param name="returnType">返回的数据类型:DBReturnType.EffectRow 为返回受影响行数;DBReturnType.IdEntity 返回最新插入主键值(isIncludeKeyColumn == false时有效)</param>
      public static int Insert<T>(T model, bool isIncludeKeyColumn, DBReturnType returnType) where T : class
      {
          int i = 0;
          Type type = typeof(T);
 
          //获取表名
          string tableName = EntityHelper.GetTableName(type);
 
          PropertyInfo[] pis = type.GetProperties();
 
          //获取所有字段和主键名称
          List<string> columns = null;
 
          //处理是否包含主键插入
          if (isIncludeKeyColumn == false)
          {
              columns = EntityHelper.GetTableColumns(pis, ColumnKeyType.Identity | ColumnKeyType.Extend, null);
          }
          else
          {
              columns = EntityHelper.GetTableColumns(pis, ColumnKeyType.Extend, null);
          }
 
          //生成INSERT语句
          StringBuilder sqlText = new StringBuilder();
          sqlText.Append("INSERT INTO ");
          sqlText.Append(tableName);
          sqlText.Append(" (");
 
          //第一个字段
          sqlText.Append(columns[0]);
 
          //第二个起所有字段
          int loop = columns.Count;
          for (i = 1; i < loop; i++)
          {
              sqlText.Append(",");
              sqlText.Append(columns[i]);
          }
 
          sqlText.Append(") VALUES (");
 
          //第一个字段
          sqlText.Append("@");
          sqlText.Append(columns[0]);
 
          //第二个起所有字段
          for (i = 1; i < loop; i++)
          {
              sqlText.Append(",@");
              sqlText.Append(columns[i]);
          }
 
          sqlText.Append(");");
 
          //生成MySqlParamter
          PropertyInfo propertyInfo = null;
 
          SqlParameter[] paras = new SqlParameter[loop];
          for (i = 0; i < loop; i++)
          {
              propertyInfo = type.GetProperty(columns[i]);
              paras[i] = new SqlParameter(columns[i], GetMySqlDbType(propertyInfo.PropertyType), -1);
              paras[i].Value = propertyInfo.GetValue(model, null);
          }
 
          //根据两种情况返回不同的值
          if (isIncludeKeyColumn == false && returnType == DBReturnType.Identity)
          {
              sqlText.Append(" SELECT @@identity AS RetId");
              SqlDataReader sdr = DataReader(sqlText.ToString(), CommandType.Text, paras);
              int keyId = 0;
              if (sdr.Read())
              {
                  keyId = Convert.ToInt32(sdr["RetId"]);
              }
              sdr.Close();
 
              return keyId;
          }
          else
          {
              return NonQuery(sqlText.ToString(), CommandType.Text, paras);
          }
      }
 
 
 
 
      #endregion
 
#region 根据Type类型获取SQL的数据类型
 
      /// <summary>
      /// 根据Type类型获取MySQL的数据类型
      /// </summary>
      /// <param name="type"></param>
      /// <returns></returns>
      private static SqlDbType GetMySqlDbType(Type type)
      {
          SqlDbType dbtype = SqlDbType.VarChar;
 
          if (type.Equals(typeof(string)))
          {
 
          }
          else if (type.Equals(typeof(int)))
          {
              dbtype = SqlDbType.Int;
          }
          else if (type.Equals(typeof(bool)))
          {
              dbtype = SqlDbType.Bit;
          }
          else if (type.Equals(typeof(DateTime)))
          {
              dbtype = SqlDbType.DateTime;
          }
          else if (type.Equals(typeof(decimal)))
          {
              dbtype = SqlDbType.Decimal;
          }
          else if (type.Equals(typeof(float)))
          {
              dbtype = SqlDbType.Float;
          }
          else if (type.Equals(typeof(double)))
          {
              dbtype = SqlDbType.Float;
          }
 
          return dbtype;
      }
 
     #endregion

下面我们简单定义一个描述数据库字段信息的Attribute 包括表名 属性字段获得

从Model模型中获取数据表名、主键名、 获取需要的读取数据源的字段集

(忘了说明表的表名写在那个地方,其实表名只需要定义在类的上面就可以了)为了简单起见我还是把目前的model放到代码里面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace FuzhuKeji
{
    [Serializable]
    [Property("TB_People")]
    public class M_People
    {
 
        string _Pl_ID;
 
        /// <summary>
        /// 主键
        /// </summary>
        [Property(ColumnKeyType.Identity)]
        public string Pl_ID
        {
            get return _Pl_ID; }
            set { _Pl_ID = value; }
        }
 
        int _PL_Age;
        
        public int PL_Age
        {
            get return _PL_Age; }
            set { _PL_Age = value; }
        }
 
        string _Pl_Sex;
     
        public string Pl_Sex
        {
            get return _Pl_Sex; }
            set { _Pl_Sex = value; }
        }
 
        string _Pl_LoginName;
         
        public string Pl_LoginName
        {
            get return _Pl_LoginName; }
            set { _Pl_LoginName = value; }
        }
 
        string _Pl_TrueName;
      
        public string Pl_TrueName
        {
            get return _Pl_TrueName; }
            set { _Pl_TrueName = value; }
        }
 
        string _PL_Pwd;
    
        public string PL_Pwd
        {
            get return _PL_Pwd; }
            set { _PL_Pwd = value; }
        }
 
    }
}

好吧这样就不用担心了映射表名获得字段的代码在下面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#region 下面我们简单定义一个描述数据库字段信息的Attribute 包括表名 属性字段获得
  public class PropertyAttribute : Attribute
  {
      public string tableName;
      public ColumnKeyType columnKeyType;
 
      /// <summary>
      /// 重构方法默认值
      /// </summary>
      public PropertyAttribute()
      {
          this.columnKeyType = ColumnKeyType.Default;
      }
 
      /// <summary>
      ///
      /// </summary>
      /// <param name="tableName"></param>
      public PropertyAttribute(string tableName)
      {
          this.tableName = tableName;
      }
 
      public PropertyAttribute(ColumnKeyType columnKeyType)
      {
          this.columnKeyType = columnKeyType;
      }
  }
 
  #endregion
 
  #region  从Model模型中获取数据表名、主键名、 获取需要的读取数据源的字段集
 
  public class EntityHelper
  {
      /// <summary>
      /// 从Model模型中获取数据表名
      /// </summary>
      public static string GetTableName(Type type)
      {
          PropertyAttribute property = (PropertyAttribute)(type.GetCustomAttributes(false)[0]);
          return property.tableName;
      }
 
 
 
      /// <summary>
      /// 从Model模型中获取数据主键名
      /// </summary>
      public static PropertyInfo GetTableIdentity(PropertyInfo[] pis)
      {
          object[] infos = null;
          PropertyAttribute attribute = null;
          foreach (PropertyInfo pi in pis)
          {
              infos = pi.GetCustomAttributes(false);
              if (infos.Length > 0)
              {
                  attribute = (PropertyAttribute)(infos[0]);
                  if (attribute.columnKeyType == ColumnKeyType.Identity)
                  {
                      return pi;
                  }
              }
          }
 
          return null;
      }
 
      /// <summary>
      /// 获取需要的读取数据源的字段集
      /// </summary>
      /// <param name="pis">Model模型所有属性集合</param>
      /// <param name="filter"></param>
      /// <param name="customColumns">自定义查询列名集合,使用逗号分隔。如不需要则为null</param>
      /// <returns></returns>
      public static List<string> GetTableColumns(PropertyInfo[] pis, ColumnKeyType filter, string customColumns)
      {
          string col = "";
          return GetTableColumns(pis, filter, customColumns, ref col);
      }
 
 
      /// <summary>
      /// 获取需要的读取数据源的字段集
      /// </summary>
      /// <param name="pis">Model模型所有属性集合</param>
      /// <param name="filter"></param>
      /// <param name="customColumns">自定义查询列名集合,使用逗号分隔。如不需要则为null</param>
      /// <returns></returns>
      public static List<string> GetTableColumns(PropertyInfo[] pis, ColumnKeyType filter, string customColumns, ref string outCol)
      {
          List<string> columns = new List<string>();
          if (customColumns != null && customColumns.Length > 0)
          {
              /*
               * 需要安全处理
               * 限制字段不包含空格
               */
              customColumns = customColumns.Trim();
              string[] strs = customColumns.Split(',');
              foreach (string str in strs)
              {
                  if (IsRegexMatch(str, @"^(\w[^\s';]+)$"))
                  {
                      columns.Add(str);
                  }
              }
 
              outCol = customColumns;
          }
          else
          {
              object[] infos = null;
              PropertyAttribute attribute = null;
              foreach (PropertyInfo pi in pis)
              {
                  //删除外部扩展对象项
                  infos = pi.GetCustomAttributes(false);
                  if (infos.Length > 0)
                  {
                      attribute = (PropertyAttribute)(infos[0]);
                      if (attribute.columnKeyType == (filter & attribute.columnKeyType))
                      {
                          continue;
                      }
                  }
                  outCol += string.Concat(",", pi.Name);
                  columns.Add(pi.Name);
              }
 
              outCol = outCol.Remove(0, 1);
          }
 
          return columns;
      }
 
     
      /// <summary>
      /// 检查是否满足某种正则表达式
      /// </summary>
      private static bool IsRegexMatch(string str, string Express)
      {
          if (string.IsNullOrEmpty(str))
          {
              return false;
          }
 
          return Regex.IsMatch(str, Express);
 
      }
  }
 
  #endregion

上面就完成了sql语句的生成:下面我就定义一个sql语句的执行就可以了。其实你到insert方法里会发现 在生产完sql语句就调用执行方法了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/// <summary>
/// 配置字符串参数
/// </summary>
private static void PrepareCommand(SqlConnection conn, SqlTransaction trans, SqlCommand sqlCommand, string sqlText, CommandType commandType, SqlParameter[] parms)
{
    if (conn.State != ConnectionState.Open)
    {
        conn.Open();
    }
 
    sqlCommand.Connection = conn;
    sqlCommand.CommandText = sqlText;
    sqlCommand.CommandType = commandType;
 
    if (trans != null)
    {
        sqlCommand.Transaction = trans;
    }
 
    if (parms != null)
    {
        foreach (SqlParameter parm in parms)
        {
            sqlCommand.Parameters.Add(parm);
        }
    }
}
 
 
/// <summary>
/// 执行SQL语句,返回数据集
/// </summary>
public static SqlDataReader DataReader(string sqlText, CommandType commandType, SqlParameter[] parms)
{
    SqlConnection conn = new SqlConnection(@"Data Source=HAOFUQI\SQLEXPRESS;Initial Catalog=Fukusuke;Persist Security Info=True;User ID=sa;pwd=123");
    SqlCommand sqlCommand = new SqlCommand();
    PrepareCommand(conn, null, sqlCommand, sqlText, commandType, parms);
 
    SqlDataReader reader = sqlCommand.ExecuteReader(CommandBehavior.CloseConnection);
 
    sqlCommand.Dispose();
    return reader;
}
 
 
/// <summary>
/// 执行SQL语句,并返回影响行数
/// </summary>
public static int NonQuery(string sqlText, CommandType commandType, SqlParameter[] parms)
{
    int reVal = 0;
    using (SqlConnection conn = new SqlConnection(@"Data Source=HAOFUQI\SQLEXPRESS;Initial Catalog=Fukusuke;Persist Security Info=True;User ID=sa;pwd=123"))
    {
        SqlCommand sqlCommand = new SqlCommand();
        PrepareCommand(conn, null, sqlCommand, sqlText, commandType, parms);
 
        reVal = sqlCommand.ExecuteNonQuery();
      
        sqlCommand.Parameters.Clear();
        sqlCommand.Dispose();
    }
 
    return reVal;
}

六、测试ORM的插入映射。

   /// <summary>
/// 执行插入语句
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button3_Click(object sender, EventArgs e)
{
M_People mp = new M_People();
mp.PL_Age = 26;
mp.Pl_ID = "001";
mp.Pl_LoginName = "Test1";
mp.PL_Pwd = "123";
mp.Pl_Sex = "男";
mp.Pl_TrueName = "张三";
int Insert_Key= DBHelper.Insert<M_People>(mp,false ,DBReturnType.Identity);
MessageBox.Show("添加成功! 插入数据的主键为:"+Insert_Key.ToString());
}

测试结果如下:

数据库插入效果:

这个地方就插入语句成功了。

七、总结。

这篇文章写得不是很好,我只是想描述,却没有一层层去剥开,也许这篇文章太长了吧。
这篇文章的核心应该是说明白如何映射如何到sql。没有分层的概念。看起来混乱,但是如果分层我就要更多篇幅讲解。

写的错误或者不好的地方还请多多批评指导。

上一篇写的是:为初学者写三层.为初学者写三层,三层的搭建和测试例子

下面准备写ORM框架,然后把生成器集成到框架中。(伪三层+ORM)+生成器+常用类库 用一个财务报销系统作为案例。

好了就写到这吧!

本文主要参考文献:

1. 什么是ORM :http://www.cnblogs.com/double1030/archive/2009/02/01/1382062.html

2.ORM硬伤 :http://www.cnblogs.com/Barton131420/archive/2007/01/07/613955.html

3反射以及Attribute在ORM中的应用:.http://blog.csdn.net/ronotian/article/details/2900714

下载地址:http://pan.baidu.com/s/1bn6bM3d

ORM,ORM的原理及测试案例的更多相关文章

  1. 为初学者写ORM,ORM的原理及测试案例

    提纲 一.什么是ORM.二.反射以及Attribute在ORM中的应用.三.创建一个数据库表和表对应的实体model.四.实体model如何映射出数据库表.五.组合ORM映射生成insert语句.六. ...

  2. Hibernate框架ORM的实现原理

    1. 什么是ORM ORM的全称是Object Relational Mapping,即对象关系映射.它的实现思想就是将关系数据库中表的数据映射成为对象,以对象的形式展现,这样开发人员就可以把对数据库 ...

  3. Storm自带测试案例的运行

    之前Storm安装之后,也知道了Storm的一些相关概念,那么怎么样才可以运行一个例子对Storm流式计算有一个感性的认识呢,那么下面来运行一个Storm安装目录自带的测试案例,我们的Storm安装在 ...

  4. 编写优美的GTest测试案例

    http://www.cnblogs.com/coderzh/archive/2010/01/09/beautiful-testcase.html 使用gtest也有很长一段时间了,这期间也积累了一些 ...

  5. nginx整合tomcat集群并做session共享----测试案例

    最近出于好奇心,研究了一下tomcat集群配置,并整合nginx,实现负载均衡,session共享,写篇记录,防止遗忘.---------菜鸡的自我修炼. 说明:博主采用一个web项目同时部署到两台t ...

  6. robotframework+selenium搭配chrome浏览器,web测试案例(搭建篇)

    这两天发布版本 做的事情有点多,都没有时间努力学习了,先给自己个差评,今天折腾了一天, 把robotframework 和 selenium 还有appnium 都研究了一下 ,大概有个谱,先说说we ...

  7. Kafka吞吐量测试案例

    Kafka吞吐量测试案例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 领英公司参考连接:https://www.slideshare.net/JiangjieQin/produc ...

  8. 运行RF测试案例,显示unable to open socket to "localhost:56505" error: [Errno 10061] 错误,且关闭RF卡死的解决办法

    问题描述: 执行WEB ui测试案例后,执行请他的测试案例显示unable to open socket to "localhost:56505" error: [Errno 10 ...

  9. 全网最详细Apache Kylin1.5安装(单节点)和测试案例

    转:http://blog.itpub.net/30089851/viewspace-2121221/ 微视频链接: Apache Kylin初识      1.版本(当前实验版本组合,版本一定要兼容 ...

随机推荐

  1. React-如何在jsx中自动补全标签(vscode)

    痛点:  React库最近的增长趋势很明显, 很多朋友都在选择学习, 很多公司也在选择使用React栈. 但在使用React库写代码的时候, 有一个很让人苦恼的问题, 就是标签在jsx语法中不能自动补 ...

  2. CentOS 6.9开启iptables的日志实现调试

    系统日志配置在CentOS 5上叫syslog,而在CentOS 6上叫rsyslog(增强版的syslog),CentOS 5上的配置文件在/etc/syslog.conf下,而CentOS 6在/ ...

  3. 解决数据库 Table 'content_tags' is marked as crashed and should be repaired 表损坏问题

    今天突然网站TAG页面打不开了,打开debug,发现提示 Table 'content_tags' is marked as crashed and should be repaired 这样的错误 ...

  4. MONO,原来你是水中月

    什么是MONO? MONO项目是由Ximian发起的,由Miguel de lcaza领导的,一个致力于开创.NET在Linux上使用的开源工程.它包含了一个C#语言的编译器,一个CLR的运行时,和一 ...

  5. java项目怎样添加jar包依赖?

    工程->右键properties->add external jars

  6. pytest文档3-pycharm运行pytest

    前言 上一篇pytest文档2-用例运行规则已经介绍了如何在cmd执行pytest用例,平常我们写代码在pycharm比较多 写完用例之后,需要调试看看,是不是能正常运行,如果每次跑去cmd执行,太麻 ...

  7. 初步理解socket

    近期研究下socket,发现自己还是有非常多不明确的地方,索性沉下心来,从最基础開始学习,開始看起,如今对自己的学习做下小小总结,以便和大家分享,如有谬误,敬请指正. 原创文章,转载请注明出处:htt ...

  8. Drawable的getIntrinsicHeight()和getIntrinsicWidth()

    版权声明:本文为博主原创文章,未经博主允许不得转载. 今天遇到一个问题,一个Bitmap封装到BitmapDrawable中 ,BitmapDrawable drawable = new Bitmap ...

  9. iOS:带主标题、副标题、图像类型的表格视图UITableView

    制作一个通讯录,包括姓名.电话.头像,将表格视图类型设置为UITableViewCellStyleSubtitle 效果图: //创建一个联系人的类,初始化数据 在视图控制器中实现表格内容的显示 #i ...

  10. Exception in thread "RMI TCP Connection(idle)" java.lang.OutOfMemoryError: PermGen space

    在Eclipse 调试 springside showcase项目中,tomcat报异常 Exception in thread "RMI TCP Connection(idle)" ...