1. ORM数据库操作原理
前面已经介绍过了个人ORM映射框架中的三个核心库:
实体—数据库 映射特性关系:
http://www.cnblogs.com/qingyuan/archive/2010/04/02/1702998.html
实体分析器:
http://www.cnblogs.com/qingyuan/archive/2010/04/05/1704546.html
Sql 语句生成组建:
http://www.cnblogs.com/qingyuan/archive/2010/04/16/1713658.html
至于这篇文章也就是这四个组件中的最后一个了------- 数据库操作库。目前.net
中对于数据库操作的模板或组件太多了,先不说微软的Linqto SQL,Linq to Entity,
还有开源组织的Hibernate克隆版NHibernate,以及前些天突然冒出来的ALinq,
号称压过Linq,有时间再研究一下。其实这些看是强大的组件框架,在其外表下面都是如出一辙,他们都是在ADO.NET中进行的封装。
不过在这个数据库操作中,都是ADO.NET进行数据库操作,但是对于对象的查询,都是泛化了的类型,也就是说我们不知道具体查询的是那张表,或者说是查询结果集是封装到那个对象,这就是本文要解决的问题。
2. ADO.NET 介绍
感觉在这里进行ADO.NET的讲解似乎是多次一举,我相信ADO.NET是每个asp.net 程序员必会的基本技能。但是这里还是简单介绍其五个核心对象吧。
Connection: Connection对象主要是开启程序和数据库之间的连结。没有利用连结对象将数据库打开,是无法从数据库中取得数据的。
Command:Command 对象主要可以用来对数据库发出一些指令,例如可以对数据库下达查询、新增、修改、删除数据等指令,以及呼叫存在数据库中的预存程序等。
DataAdapter: DataSetCommand对象主要是在数据源以及DataSet 之间执行数据传输的工作,它可以透过Command 对象下达命令后,并将取得的数据放入DataSet 对象中。
DataSet:DataSet 这个对象可以视为一个暂存区(Cache),可以把从数据库中所查询到的数据保留起来,甚至可以将整个数据库显示出来。DataSet 的能力不只是可以储存多个Table 而已,还可以透过DataSetCommand 对象取得一些例如主键等的数据表结构,并可以记录数据表间的关联。DataSet 对象可以说是ADO.NET
中重量级的对象,这个对象架构在DataSetCommand 对象上,本身不具备和数据源沟通的能力。
DataReader: 当我们只需要循序的读取数据而不需要其它操作时,可以使用DataReader 对象。DataReader对象只是一次一笔向下循序的读取数据源中的数据,而且这些数据是只读的,并不允许作其它的操作。因为DataReader 在读取数据的时候限制了每次只读取一笔,而且只能只读,所以使用起来不但节省资源而且效率很好.
老生常谈的说了一遍ADO.NET 的五个核心对象,这里主要目的是为了更好的了解此篇文章。我想现在用Linq to SQL , Linq to Entity 的人太多了,或许都忘记了ADO.NET 的基本操作,其实我本人也是如此,一段时间不是用好多忘记了,这里再次复习一遍ADO.NET 能更好的理解此篇文章。
3. 数据库加载驱动操作接口
该数据库操作接口很简单,就是封装了一些数据库操作的常用接口和命令,并定义了一些数据库连接和关闭的方法,并控制了数据库事务提交和回滚的方法。不过在这里的方法实现中我并没有对事务进行处理,如果对本文有兴趣的人可以在后期的文章中关注,我会对此进行补充。
下面简单看看数据库加载驱动接口:
2 * 2010-2-2
3 *
4 * 情 缘
5 *
6 * 数据库提供加载驱动接口,该接口继承IDisposable,
7 * 用于释放对象占用的内存。该接口定义了数据库链接
8 * 语句,链接对象,执行命令,适配器模式接口。同时
9 * 还提供了打开数据库连接和关闭的方法,还有三个方
10 * 法是用于控制数据库操作事务
11 *
12 * */
13
14 using System;
15 using System.Collections.Generic;
16 using System.Linq;
17 using System.Text;
18 using System.Data;
19
20 namespace CommonData.Data.Core
21 {
22 public interface IDbProvider:IDisposable
23 {
24 /// <summary>
25 /// 数据库链接语句
26 /// </summary>
27 string ConnectionString { get; set; }
28
29 /// <summary>
30 /// 数据库连接对象
31 /// </summary>
32 IDbConnection Connection { get; set; }
33
34 /// <summary>
35 /// 数据库操作命令
36 /// </summary>
37 IDbCommand Command { get; set; }
38
39 /// <summary>
40 /// 数据库操作适配器
41 /// </summary>
42 IDbDataAdapter Adapter { get; set; }
43
44 /// <summary>
45 /// 打开数据库连接方法
46 /// </summary>
47 void Open();
48
49 /// <summary>
50 /// 关闭数据库连接方法
51 /// </summary>
52 void Close();
53
54 /// <summary>
55 /// 开始事务控制方法
56 /// </summary>
57 void BeginTransaction();
58
59 /// <summary>
60 /// 事务回滚方法
61 /// </summary>
62 void RollBack();
63
64 /// <summary>
65 /// 事务提交方法
66 /// </summary>
67 void Commit();
68 }
69 }
70
这里数据库操作的常用对象都是采用的顶层的接口作为属性。至于为什么使用接口,它的好处已经说的太多了,次数也很多了,这里就不再多说。而public
interface IDbProvider:IDisposable
集成这个接口,让程序自动管理对象,释放对象占用内存空间。
简单的看看SQL Server 数据库加载驱动操作类:
2 * 2010-2-2
3 *
4 * 情 缘
5 *
6 * SQL Server 数据库操作基本对象
7 * 该类实现了IDbProvider 接口。
8 *
9 * */
10 using System;
11 using System.Collections.Generic;
12 using System.Linq;
13 using System.Text;
14 using System.Data.SqlClient;
15 using System.Data;
16
17 namespace CommonData.Data.Core.SQLCore
18 {
19 public class SqlProvider : IDbProvider
20 {
21 private string connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["DataBaseConfig"].ConnectionString;
22 /// <summary>
23 /// 数据库连接字符串
24 /// </summary>
25 public string ConnectionString
26 {
27 get
28 {
29 if (connectionString == null)
30 {
31 connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["DataBaseConfig"].ConnectionString;
32 }
33 return connectionString;
34 }
35 set
36 {
37 connectionString = value;
38 }
39 }
40
41 private IDbConnection connection = null;
42 /// <summary>
43 /// 数据库连接对象
44 /// </summary>
45 public IDbConnection Connection
46 {
47 get
48 {
49 if (connection == null)
50 {
51 connection = new SqlConnection(connectionString);
52 }
53 return connection;
54 }
55 set
56 {
57 connection = value;
58 }
59 }
60
61 private IDbCommand command = null;
62 /// <summary>
63 /// 数据库命令操作对象
64 /// </summary>
65 public IDbCommand Command
66 {
67 get
68 {
69 if (command == null)
70 {
71 command = new SqlCommand();
72 command.Connection = connection;
73 }
74 return command;
75 }
76 set
77 {
78 command = value;
79 }
80 }
81
82 private IDbDataAdapter adapter = null;
83 /// <summary>
84 /// 数据库适配器对象
85 /// </summary>
86 public IDbDataAdapter Adapter
87 {
88 get
89 {
90 if (adapter == null)
91 {
92 adapter = new SqlDataAdapter(command as SqlCommand);
93 }
94 return adapter;
95 }
96 set
97 {
98 adapter = value;
99 }
100 }
101
102 /// <summary>
103 /// 数据库事务对象
104 /// </summary>
105 private IDbTransaction transaction = null;
106
107 /// <summary>
108 /// 打开数据库连接
109 /// </summary>
110 public void Open()
111 {
112 if (connection != null)
113 {
114 connection.Open();
115 }
116 }
117
118 /// <summary>
119 /// 关闭数据库连接
120 /// </summary>
121 public void Close()
122 {
123 if (connection != null)
124 {
125 connection.Close();
126 }
127 }
128
129 /// <summary>
130 /// 开始事务
131 /// </summary>
132 public void BeginTransaction()
133 {
134 transaction = connection.BeginTransaction();
135 command.Transaction = transaction;
136 }
137
138 /// <summary>
139 /// 事务回滚
140 /// </summary>
141 public void RollBack()
142 {
143 if (transaction != null)
144 {
145 transaction.Rollback();
146 command.Transaction = null;
147 transaction.Dispose();
148 }
149 }
150
151 /// <summary>
152 /// 事务提交
153 /// </summary>
154 public void Commit()
155 {
156 if (transaction != null)
157 {
158 transaction.Commit();
159 command.Transaction = null;
160 transaction.Dispose();
161 }
162 }
163
164 /// <summary>
165 /// 创建数据库加载驱动
166 /// </summary>
167 /// <returns></returns>
168 public IDbProvider CreateInstance()
169 {
170 return new SqlProvider();
171 }
172
173 /// <summary>
174 /// 释放内存空间
175 /// </summary>
176 public void Dispose()
177 {
178 GC.SuppressFinalize(this);
179 }
180 }
181 }
182
对于其他的数据库来说,使用操作的对象和命令都不同,他是它们都提供抽象出来了一个公共接口就是IDbProvider (数据提供加载驱动)。在接口中定义的每个getset 方法都进行了实现实现了一个属性的封装,并且提供了唯一对象的变量。(C#中属性的封装其实也就是一个get,set方法,所以在接口中能够这样定义方法)
4. 数据库的操作命令
ADO.NET 中查询数据库,返回的结果分为多种情况,而数据库的操作无非就四种情况增删改查.
而这四种情况又可以分为两大类:
(1). 数据库的修改操作: 数据的增加,修改,删除都对数据进行了操作,都有写的动作,对数据结构有了变动。
(2). 数据库的查询操作:数据库的查询,也就是读取数据,这个操作不会对数据的数据结构进行修改,因此这里可以单独分为一类。当然一类也就是比较复杂的一类了,查询的情况会很多不同。
下面是数据库操作的接口:
2 * 2010-3-5
3 *
4 * 情 缘
5 *
6 * 该接口定义了数据库操作的各种方法,该接口定义
7 * 工作职责比较明确,只是针对数据的操作,不需要
8 * 管理数据库的连接等过程。此接口还包含了一个数
9 * 据流和集合类型的转换的方法定义
10 *
11 * */
12 using System;
13 using System.Collections.Generic;
14 using System.Linq;
15 using System.Text;
16 using System.Data;
17
18 namespace CommonData.Data.Core
19 {
20 public interface IBaseHelper:IDisposable
21 {
22 /// <summary>
23 /// 返回受影响行数
24 /// </summary>
25 /// <param name="provider">数据提供加载驱动</param>
26 /// <param name="sqlString">sql语句</param>
27 /// <returns></returns>
28 int ExecuteNonQuery(IDbProvider provider, string sqlString);
29
30 /// <summary>
31 /// 返回受影响行数
32 /// </summary>
33 /// <param name="provider">数据提供加载驱动</param>
34 /// <param name="sqlString">sql语句</param>
35 /// <param name="isProcedure">是否为存储过程</param>
36 /// <returns></returns>
37 int ExecuteNonQuery(IDbProvider provider, string sqlString, bool isProcedure);
38
39 /// <summary>
40 /// 返回受影响行数
41 /// </summary>
42 /// <param name="provider">数据提供加载驱动</param>
43 /// <param name="sqlString">sql语句</param>
44 /// <param name="param">sql语句对应参数</param>
45 /// <returns></returns>
46 int ExecuteNonQuery(IDbProvider provider, string sqlString, params IDataParameter[] param);
47
48 /// <summary>
49 /// 返回受影响行数
50 /// </summary>
51 /// <param name="provider">数据提供加载驱动</param>
52 /// <param name="sqlString">sql语句</param>
53 /// <param name="isProcedure">是否为存储过程,true 为存储过程</param>
54 /// <param name="param">sql语句对应参数</param>
55