博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ORM,ORM的原理及测试案例
阅读量:5761 次
发布时间:2019-06-18

本文共 18202 字,大约阅读时间需要 60 分钟。

 

 

提纲

一、什么是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实体了,下面我们就通过反射的方法来动态获取此映射规则:

 

///         ///  测试映射        ///         ///         ///         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,我们定义了类属性和数据库字段的一一对应关系。

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

 

///         /// 反射+Attribute 映射出数据库表        ///         ///         ///         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的插入映射。

///         ///  执行插入语句        ///         ///         ///         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
(mp,false ,DBReturnType.Identity); MessageBox.Show("添加成功! 插入数据的主键为:"+Insert_Key.ToString()); }

测试结果如下:

 

数据库插入效果:

 

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

 

 

七、总结。

 

这篇文章写得不是很好,我只是想描述,却没有一层层去剥开,也许这篇文章太长了吧。

这篇文章的核心应该是说明白如何映射如何到sql。没有分层的概念。看起来混乱,但是如果分层我就要更多篇幅讲解。

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

 

上一篇写的是:为初学者写三层.

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

好了就写到这吧!

 

本文主要参考文献:

1. 什么是ORM :

2.ORM硬伤 :

3反射以及Attribute在ORM中的应用:.

 

转载地址:http://rxlkx.baihongyu.com/

你可能感兴趣的文章
PyCharm切换解释器
查看>>
jmp far ptr s所对应的机器码
查看>>
css详解1
查看>>
【转载】Presentation at from Yoshua Bengio
查看>>
MySQL类型转换
查看>>
HashSet HashMap 源码阅读笔记
查看>>
变量声明提升1
查看>>
轻量级的Java 开发框架 Spring
查看>>
JS之路——浏览器window对象
查看>>
Chrome教程(二)使用ChromeDevTools命令菜单运行命令
查看>>
数据结构及算法基础--快速排序(Quick Sort)(二)优化问题
查看>>
你对position的了解到底有多少?
查看>>
随笔2013/2/19
查看>>
Windows Phone的Silverlight Toolkit 安装及其使用
查看>>
DBS:同学录
查看>>
Mysql备份系列(1)--备份方案总结性梳理
查看>>
[CareerCup] 1.6 Rotate Image 翻转图像
查看>>
Python中的画图初体验
查看>>
Java程序员的日常 —— 响应式导航Demo
查看>>
objective-c内存管理基础
查看>>