第一次写东西 各位大大海涵
一个系统执行一个数据操作的步骤:
1.连接数据库。
2.构建Sql 语句。
3.执行语句。
4.返回 执行结果。
实例代码下载实例代码下载
注:
一个系统可能有 N 个操作 ,然后另一个系统也要执行数据访问操作,那么我们可以不可以把连接数据、库执行语句、返回结果
写成一个公共的东西呢? 答案是一定的。例如:NHibernate 我们只要引用它的类库、配置数据库连接语句和Mapping 文件 就可以
进行操作了。那我今天说的是 不用写配置文件 的一个 公用数据库操作类库。暂时只实现查询
首先我们编写一个接口:
![]()
IDataProvider
using System;
using System.Collections.Generic;
using System.Text;
using System.Data.Common;
using System.Data;
namespace CustomDataOperate.Data.DataProviders
{
public interface IDataProvider
{
DbConnection OpenConnection();
void Open();
void Close();
IDataReader ExecuteReader(string sql);
int ExecuteNonQuery(string sql);
ICollection<TEntity> ExcuteReader<TEntity>(string sql) where TEntity : class;
}
}
DbConnection OpenConnection(); 打开一个数据库连接
void Open(); 当连接为关闭状态时 再次打开连接
void Close(); 关闭连接
IDataReader ExecuteReader(string sql); 执行Sql 语句返回执行结果
int ExecuteNonQuery(string sql); 执行 修改、删除、增加
ICollection<TEntity> ExcuteReader<TEntity>(string sql) where TEntity : class; 执行查询返回对象集合
然后为接口写一个抽象类:
![]()
DataProviderBase
using System;
using System.Collections.Generic;
using System.Text;
using System.Data.Common;
using CustomDataOperate.Data.Translates;
using System.Data;
namespace CustomDataOperate.Data.DataProviders
{
public abstract class DataProviderBase : IDataProvider
{
protected DbConnection _Connection;
protected DbCommand _Command;
protected IEntityTranslate _Translate;
#region IDataProvider Members
public abstract DbConnection OpenConnection();
public virtual void Close()
{
_Connection.Close();
}
public virtual void Open()
{
_Connection.Open();
}
protected virtual DbCommand Command
{
get { return _Command; }
set { _Command = value; }
}
protected IEntityTranslate Translate
{
get
{
if (_Translate == null)
{
_Translate = new EntityTranslate();
}
return _Translate;
}
}
public abstract IDataReader ExecuteReader(string sql);
public abstract int ExecuteNonQuery(string sql);
public abstract ICollection<TEntity> ExcuteReader<TEntity>(string sql) where TEntity : class;
#endregion
}
在 DataProviderBase 中出现了 Translate 属性 他是什么呢 ? 他是一个 (IEntityTranslate) 转换器
将IDataReader 转换为Entity
代码如下:![]()
![]()
IEntityTranslate
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
namespace CustomDataOperate.Data.Translates
{
public interface IEntityTranslate
{
TEntity Translate<TEntity>(IDataReader reader) where TEntity : class;
}
}
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using MD = CustomDataOperate.Data.Attributes;
using System.Reflection;
namespace CustomDataOperate.Data.Translates
{
public class EntityTranslate:IEntityTranslate
{
public TEntity Translate<TEntity>(IDataReader reader) where TEntity : class
{
Type entityType = typeof(TEntity);
object entity = Activator.CreateInstance(entityType);
foreach (PropertyInfo info in entityType.GetProperties())
{
string columnName = string.Empty;
object[] attributes = info.GetCustomAttributes(true);
foreach (object attribute in attributes)
{
if (attribute is MD.DataColumn)
{
columnName = (attribute as MD.DataColumn).ColumnName;
int filedIndex = 0;
while (filedIndex < reader.FieldCount)
{
if (reader.GetName(filedIndex) == columnName)
{
info.SetValue(entity, reader.GetValue(filedIndex), null);
break;
}
filedIndex++;
}
break;
}
}
}
return entity as TEntity;
}
}
}
为什么转换器中会出现 DataColumn 是 System.Data 命名空间下的吗? 不是 这是一个自定义的 Attirbute
![]()
DataColumn
using System;
using System.Collections.Generic;
using System.Text;
namespace CustomDataOperate.Data.Attributes
{
public class DataColumn : System.Attribute
{
public DataColumn()
{
}
public DataColumn(string columnName)
{
ColumnName = columnName;
}
public string ColumnName
{
get;
set;
}
}
}
注释:
ColumnName :将数据库的Filed 和 Entity Property 对应。
到这里还要做什么呢? 对了还缺少实现,那么我们开始实现这个 Provider
![]()
SqlDataProvider
using System;
using System.Collections.Generic;
using System.Text;
using CustomDataOperate.Data.DataProviders;
using System.Data.Common;
using System.Configuration;
using System.Data.SqlClient;
using System.Data;
namespace CustomDataOperate.Data.SqlDataProviders
{
public class SqlDataProvider :DataProviderBase
{
private void BuilderCommand(string sql)
{
Command.CommandText = sql;
Command.Connection = OpenConnection();
}
public override System.Data.Common.DbConnection OpenConnection()
{
if (_Connection == null)
{
_Connection = BuilderSqlConnection();
}
if (_Connection.State != System.Data.ConnectionState.Open)
{
Open();
}
return _Connection;
}
private System.Data.Common.DbConnection BuilderSqlConnection()
{
try
{
string connectionString = ConfigurationManager.ConnectionStrings["DataBaseConnectionString"].ConnectionString;
return new SqlConnection(connectionString);
}
catch (Exception ex)
{
throw new Exception("數據庫鏈接失敗! 失敗原因:" + ex);
}
}
protected override System.Data.Common.DbCommand Command
{
get
{
if (base.Command == null)
{
base.Command = new SqlCommand();
}
return base.Command;
}
set
{
base.Command = value;
}
}
public override IDataReader ExecuteReader(string sql)
{
BuilderCommand(sql);
return Command.ExecuteReader();
}
public override int ExecuteNonQuery(string sql)
{
BuilderCommand(sql);
return Command.ExecuteNonQuery();
}
public override ICollection<TEntity> ExcuteReader<TEntity>(string sql)
{
ICollection<TEntity> datas = new List<TEntity>();
BuilderCommand(sql);
using (IDataReader reader = Command.ExecuteReader())
{
while (reader.Read())
{
datas.Add(Translate.Translate<TEntity>(reader));
}
}
return datas;
}
}
好了准备工作做好了!那么我们开始测试吧:
既然测试那么不能少了数据库:
CREATE TABLE Customer(
[CustomerID] [int] NOT NULL,
[CustomerName] [nvarchar](50) COLLATE Chinese_PRC_CI_AS NOT NULL,
)
添加两条数据:
100001 測試修改客戶1212
100002 SecondCus
准备一个Entity:
![]()
Customer
public class Customer
{
public Customer()
{}
public Customer(int customerID,string customerName)
{
CustomerID =customerID;
CustomerName =customerName;
}
[DataColumn("CustomerID")]
public int CustomerID
{
get;
set;
}
[DataColumn("CustomerName")]
public string CustomerName
{
get;
set;
}
}
是不是发现 Entity中出现了 [DataColumn("CustomerID")] 呢! 对了 这里就是将数据库的列和Entity对应上。
伟大的时刻要即将到来:
![]()
Test
private IDataProvider _Provider;
[TestInitialize]
public void Init()
{
_Provider = new SqlDataProvider();
}
[TestMethod()]
public void ExcuteReaderTest()
{
string sql = "select * from customer";
ICollection<Customer> customers = _Provider.ExcuteReader<Customer>(sql);
Assert.IsNotNull(customers);
foreach (Customer customer in customers)
{
Console.WriteLine("{0} {1}", customer.CustomerID, customer.CustomerName);
}
输出结果:
100001 測試修改客戶1212
100002 SecondCus
Yes 成功了!