ORM,ORM的原理及测试案例

提纲

一、什么是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

时间: 2024-10-25 18:02:16

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

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

提纲 一.什么是ORM.二.反射以及Attribute在ORM中的应用.三.创建一个数据库表和表对应的实体model.四.实体model如何映射出数据库表.五.组合ORM映射生成insert语句.六.测试ORM的插入映射.七.总结. 内容: 一 .什么是ORM? 概念: 对象关系映射(Object Relational Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序技术,用于实现面向对象编程语言里不同类型系统的数据之间的转换. 详细介绍:  让我们从O/R开始.字

.net开发之我见,or实现 最简 优化法。knock out type convert 与我之简化orm的实现原理及实现细则,最简化开发法

现在的.net or构架,大家认同的各种大大小小,ef,subsonic,nhibernate,甚至小一些的petapoco这种,但用过的人我想他们考虑的是比较多. 小一些的Petapoco也有几千行的代码. 而有一些或是配置困难,或是脱离不了一些sql, 而我一直在寻找一种更简便的方法简化自己的开发,使自己更容易的操作数据. 由于最近在用mysql,而mysql使用myism引擎和innodb引擎时,由于Innodb引擎支持更广泛些,事务等,虽然在字符索引上可能较myism差些,不过用是必须可

Hibernate框架ORM的实现原理

1. 什么是ORM ORM的全称是Object Relational Mapping,即对象关系映射.它的实现思想就是将关系数据库中表的数据映射成为对象,以对象的形式展现,这样开发人员就可以把对数据库的操作转化为对这些对象的操作.因此它的目的是为了方便开发人员以面向对象的思想来实现对数据库的操作. 2.什么是Hibernate 对于Hibernate的称呼有很多,比如工具.技术.框架以及解决方案等,这些都可以,重要的是大家要知道它的作用.在这里我习惯性称它为框架,它是一种能实现ORM的框架.能实

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

最近出于好奇心,研究了一下tomcat集群配置,并整合nginx,实现负载均衡,session共享,写篇记录,防止遗忘.---------菜鸡的自我修炼. 说明:博主采用一个web项目同时部署到两台tomcat下,(tomcat-A,tomca-B),使用nginx做反向代理,按照设置的权值,将请求分发到后台的tomcatA/tomcat-B,并且实现session共享. 配置好本地域名指向:修改host文件:添加 127.0.0.1  www.domain.com.cn 新建项目:tiny-d

[测试案例]页面CPU使用率测试

1. 场景描述 测试网站某页面注册表单,该表单包含若干个文本输入框以及两个密码输入框:登录密码和确认密码.登录密码只能由数字或字母组成,并且长度在6-20个字符之间,确认密码必须与登录密码完全一致,当满足以上所有条件后,才能成功提交注册表单,否则提交时将在不符合要求的输入框右侧提示对应的错误信息. 2. 问题说明 在Chrome浏览器下对登录密码和确认密码输入框进行反复输入测试时,发现浏览器的CPU占有率会不断上升,导致页面出现卡顿.无响应的情况,但是在相同浏览器下测试其他文本输入框或在其他浏览

(二)语音合成测试案例

上一章节大致描述了一下.NET Framework中的语音识别和语音合成的应用开发接口.接下来以一个测试案例来展示下SAPI的使用.以下案例均已VS2010 + Framework4.0为例. 用VS新建一个窗体应用程序.并添加引用. 测试程序界面布局如下: 下面是完成的代码: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.D

测试案例小问题

测试案例小问题

一个测试案例的分析

案例: 某软件公司在开发一个城镇居民保险系统时,在单元测试.集成测试阶段,为了追赶进度,开发人员与测试人员都没有介入测试工作. 系统测试阶段,测试小组借助缺陷管理工具和开发人员交互进行测试与缺陷修复工作.期间,发现"扭转文档无法归档"的严重错误,开发人员在修改时,认为难度太大,决定暂停修改,得到测试人员认可.在产品发布前,该问题在开发环境下得到解决. 回归测试结束后,开发人员把开发环境下的产品打包,发送给客户. 分析:在案例中,有几处显然不合理的地方: 1.测试介入太晚 2.回归测试做

软件工程--构建之法--功能测试 设计10个或者更多的测试案例完成对钉书钉的功能测试

设计10个或者更多的测试案例完成对钉书钉的功能测试 (1)使用不同的纸质材料厚度,使用相同规格钉书钉,查看钉书器是否正常工作 (2)使用不同规格的钉书钉,使用相同厚度的纸质材料,查看钉书器是否正常工作 (3)测试钉书器在不同的使用方式下使用,查看钉书器是否异常 (4)测试钉书器总的使用次数 (5)测试钉书器订材料后,美观次数 (6)测试钉书器钉材料后,不美观次数 (7)测试钉书器在不同温度条件下,查看钉书器是否正常工作 (8)测试钉书器在不同湿度条件下,查看钉书器是否正常工作 (9)使用不同材料