开篇

2016新年伊始,望眼过去,不知不觉在博客园已经注册8个月啦,由于最近忙于工作,博客迟迟没有更新。直到最近一直研究.Net设计模式,对一些模式有所感悟,故拿出自己的心得与大家分享,在接下来的所有博客中我都会以【理论介绍】和【具体实践】两个方面来叙述对模式的应用。

理论介绍

仓储(Respository)是存在于工作单元和数据库之间单独分离出来的一层,是对数据访问的封装。其优点:

    1)业务层不需要知道它的具体实现,达到了分离关注点。

    2)提高了对数据库访问的维护,对于仓储的改变并不会改变业务的逻辑,数据库可以用Sql Server(该系列博客使用)、MySql等。

具体实践

首先,创建IRepository.cs接口定义对数据操作的契约(命令执行、重载不同查询结果集合、查询实体、查询返回结果值)。

     /// <summary>
/// Ado.Net实现的仓储
/// </summary>
public interface IRepository
{
/// <summary>
/// 增、删、改对象
/// </summary>
/// <param name="commandText">Sql语句</param>
/// <param name="parameters">参数</param>
/// <param name="isCommit">是否提交</param>
/// <returns></returns>
void Command(string commandText, IDictionary<string, object> parameters = null); /// <summary>
/// 查询对象集合
/// </summary>
/// <typeparam name="T">返回值的实体类型</typeparam>
/// <param name="commandText">Sql语句</param>
/// <param name="parameters">参数</param>
/// <param name="isCommit">是否提交</param>
/// <returns>泛型实体集合</returns>
List<T> QueryAll<T>(string commandText, IDictionary<string, object> parameters = null) where T : class, new(); /// <summary>
/// 查询对象集合
/// </summary>
/// <param name="commandText"></param>
/// <param name="type"></param>
/// <param name="parameters"></param>
/// <param name="isCommit"></param>
/// <returns></returns>
List<object> QueryAll(string commandText, Type type, IDictionary<string, object> parameters = null); /// <summary>
/// 查询对象
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="commandText"></param>
/// <param name="type"></param>
/// <param name="parameters"></param>
/// <returns></returns>
T Query<T>(string commandText, IDictionary<string, object> parameters = null) where T : class,new(); /// <summary>
/// 查询数量
/// </summary>
/// <param name="commandText"></param>
/// <param name="parameters"></param>
/// <returns></returns>
object QueryCount(string commandText, IDictionary<string, object> parameters = null);
}

其次,定义抽象类BaseRepository.cs实现仓储。

     /// <summary>
/// 基础库实现
/// </summary>
public abstract class BaseRepository : IRepository
{
/// <summary>
/// 数据库连接字符串标识
/// </summary>
public abstract string Key { get; } private SqlConnection connection; private SqlConnection Connection
{
get
{
if (connection == null)
{
ConnectionStringSettings settings = ConfigurationManager.ConnectionStrings[Key];
connection = new SqlConnection(settings.ConnectionString);
}
return connection;
}
} /// <summary>
/// 增、删、改命令
/// </summary>
/// <param name="commandText"></param>
/// <param name="parameters"></param>
public virtual void Command(string commandText, IDictionary<string, object> parameters = null)
{
Func<SqlCommand, int> excute = (commend) =>
{
return commend.ExecuteNonQuery();
};
CreateDbCommondAndExcute<int>(commandText, parameters, excute);
} /// <summary>
/// 查询实体(强类型)
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="commandText"></param>
/// <param name="parameters"></param>
/// <returns></returns>
public virtual T Query<T>(string commandText, IDictionary<string, object> parameters = null,Func<IDataReader, T> load = null) where T : class, new()
{
Func<SqlCommand, T> excute = (dbCommand) =>
{ var result = default(T);
using (IDataReader reader = dbCommand.ExecuteReader())
{
while (reader.Read())
{
if (load == null)
{
load = (s) => { return s.GetReaderData<T>(); };
}
result = load(reader);
}
return result;
}
};
return CreateDbCommondAndExcute<T>(commandText, parameters, excute);
} /// <summary>
/// 查询匿名对象集合
/// </summary>
/// <param name="commandText"></param>
/// <param name="type"></param>
/// <param name="parameters"></param>
/// <returns></returns>
public virtual List<object> QueryAll(string commandText, Type type, IDictionary<string, object> parameters = null,Action<dynamic> setItem = null)
{
Func<SqlCommand, List<object>> excute = (dbCommand) =>
{
var result = new List<object>(); using (IDataReader dataReader = dbCommand.ExecuteReader())
{
while (dataReader.Read())
{
var item = dataReader.GetReaderData(type);
if (setItem != null)
{
setItem(item);
}
result.Add(item);
}
}
return result;
};
return CreateDbCommondAndExcute<List<object>>(commandText, parameters,
excute);
} /// <summary>
/// 查询强类型对象集合
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="commandText"></param>
/// <param name="parameters"></param>
/// <returns></returns>
public virtual List<T> QueryAll<T>(string commandText, IDictionary<string, object> parameters = null,Func<IDataReader, T> load = null) where T : class, new()
{
Func<SqlCommand, List<T>> excute = (dbCommand) =>
{
List<T> result = new List<T>();
using (IDataReader reader = dbCommand.ExecuteReader())
{
while (reader.Read())
{
if (load == null)
{
load = (s) => { return s.GetReaderData<T>(); };
}
var item = load(reader);
result.Add(item);
}
return result;
}
};
return CreateDbCommondAndExcute(commandText, parameters, excute);
} /// <summary>
/// 查询结果数量
/// </summary>
/// <param name="commandText"></param>
/// <param name="parameters"></param>
/// <returns></returns>
public virtual object QueryCount(string commandText, IDictionary<string, object> parameters = null)
{
Func<SqlCommand, object> excute = (dbCommand) =>
{
return dbCommand.ExecuteScalar();
};
return CreateDbCommondAndExcute(commandText, parameters, excute);
} /// <summary>
/// 创建命令并执行
/// </summary>
/// <typeparam name="TValue"></typeparam>
/// <param name="commandText"></param>
/// <param name="parameters"></param>
/// <param name="excute"></param>
/// <returns></returns>
private TValue CreateDbCommondAndExcute<TValue>(string commandText,
IDictionary<string, object> parameters, Func<SqlCommand, TValue> excute)
{
if (Connection.State == ConnectionState.Closed) { Connection.Open(); };
using (SqlCommand command = new SqlCommand())
{
command.CommandType = CommandType.Text;
command.CommandText = commandText;;
command.Connection = Connection;
command.SetParameters(parameters);
return excute(command);
}
} /// <summary>
/// 关闭连接
/// </summary>
public void Dispose()
{
if (connection != null)
{
Connection.Dispose();//非托管资源
}
}
}

最后,实现方法中的扩展方法。

     /// <summary>
/// Sql Server 扩展类
/// </summary>
public static class SqlServerExtension
{
/// <summary>
/// 设置参数
/// </summary>
/// <param name="dbCommand"></param>
/// <param name="parameters"></param>
public static void SetParameters(this IDbCommand dbCommand, IDictionary<string, object> parameters)
{
if (parameters == null)
{
return;
}
foreach (var parameter in parameters)
{
if (parameter.Value != null)
{
dbCommand.Parameters.Add(new SqlParameter(parameter.Key, parameter.Value));
}
else
{
dbCommand.Parameters.Add(new SqlParameter(parameter.Key,DBNull.Value));
}
}
} /// <summary>
/// 获取对应的实体
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="TEntity"></param>
/// <returns></returns>
public static TEntity GetReaderData<TEntity>(this IDataReader reader) where TEntity : class, new()
{
var item = new TEntity();
var filedList = new List<string>();
for (int i = ; i < reader.FieldCount; i++)
{
filedList.Add(reader.GetName(i));
}
//映射数据库中的字段到实体属性
IEnumerable<PropertyInfo> propertys = typeof(TEntity).GetProperties().Where(s => filedList.Contains(s.Name));
foreach (var property in propertys)
{
//对实体属性进行设值
property.SetValue(item, reader[property.Name]);
}
return item;
} /// <summary>
/// 根据列名获取值
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="reader"></param>
/// <param name="columnName"></param>
/// <returns></returns>
public static T GetValue<T>(this IDataReader reader, string columnName)
{
int index = reader.GetOrdinal(columnName);
if (reader.IsDBNull(index))
{
return default(T);
}
return (T)reader[index];
} /// <summary>
/// 获取对应的实体
/// </summary>
/// <param name="reader"></param>
/// <param name="type"></param>
/// <returns></returns>
public static object GetReaderData(this IDataReader reader,Type type)
{
var item = Activator.CreateInstance(type);
var filedList = new List<string>();
for (int i = ; i < reader.FieldCount; i++)
{
filedList.Add(reader.GetName(i).ToLower());
}
var properties = (from s in type.GetProperties()
let name = s.Name.ToLower().Split(new string[] { "_" }, StringSplitOptions.RemoveEmptyEntries).LastOrDefault()
where filedList.Contains(s.Name)
select new
{
Name = s.Name,
Property = s
}).ToList(); foreach (var property in properties)
{
property.Property.SetValue(item, reader[property.Name]);
}
return item;
}
}

至此,使用Ado.Net 实现的仓储完成啦!当然这只是非泛型版本。当需要使用ORM时,该系列会同步更新泛型版本的实现对聚合类的持久化操作的仓储模式。

后记

相信各位广大园友看到这里,一定不难看出这和DAL层好像没什么区别,没错,对于非泛型的仓储实现等同于DAL层。有人可能会认为这是一种多余的设计,对于未使用ORM的数据存储来说,这里也就只是提供一种额外的设计思路罢了。

在接下来的一篇中将实现数据访问逻辑和领域层完全解耦。

【.Net设计模式系列】仓储(Repository)模式 ( 一 )的更多相关文章

  1. Android设计模式系列--工厂方法模式

    工厂方法模式,往往是设计模式初学者入门的模式,的确,有人称之为最为典型最具启发效果的模式.android中用到了太多的工厂类,其中有用工厂方法模式的,当然也有很多工厂并不是使用工厂方法模式的,只是工具 ...

  2. [js高手之路]设计模式系列课程-组合模式+寄生组合继承实战新闻列表

    所谓组合模式,就是把一堆结构分解出来,组成在一起,现实中很多这样的例子,如: 1.肯德基套餐就是一种组合模式, 比如鸡腿堡套餐,一般是是由一个鸡腿堡,一包薯条,一杯可乐等组成的 2.组装的台式机同理, ...

  3. Java设计模式系列-抽象工厂模式

    原创文章,转载请标注出处:https://www.cnblogs.com/V1haoge/p/10755412.html 一.概述 抽象工厂模式是对工厂方法模式的再升级,但是二者面对的场景稍显差别. ...

  4. Java设计模式系列-工厂方法模式

    原创文章,转载请标注出处:<Java设计模式系列-工厂方法模式> 一.概述 工厂,就是生产产品的地方. 在Java设计模式中使用工厂的概念,那就是生成对象的地方了. 本来直接就能创建的对象 ...

  5. Java设计模式系列-装饰器模式

    原创文章,转载请标注出处:<Java设计模式系列-装饰器模式> 一.概述 装饰器模式作用是针对目标方法进行增强,提供新的功能或者额外的功能. 不同于适配器模式和桥接模式,装饰器模式涉及的是 ...

  6. 设计模式系列之迭代器模式(Iterator Pattern)——遍历聚合对象中的元素

    模式概述 模式定义 模式结构图 模式伪代码 模式改进 模式应用 模式在JDK中的应用 模式在开源项目中的应用 模式总结 说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修 ...

  7. 设计模式系列之建造者模式(Builder Pattern)——复杂对象的组装与创建

    说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...

  8. 设计模式系列之工厂模式三兄弟(Factory Pattern)

    说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...

  9. 设计模式系列之组合模式(Composite Pattern)——树形结构的处理

    说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...

随机推荐

  1. linux服务器安装oracle

    Linux安装Oracle 11g服务器(图文) 应该是最完整的Oracle安装教程了,全程在测试服务器上完成,软件环境:Red Hat Enterprise Linux 6:Oracle 11g ( ...

  2. NOI2000 青蛙过河[递推]

    也许更好的阅读体验 \(\mathcal{Description}\) 原题链接: Comet OJ 洛谷 大小各不相同的一队青蛙站在河左岸的石墩(记为A)上,要过到对岸的石墩(记为D)上去.河心有几 ...

  3. javascript 之 扩展对象

    注意点:在js中常见的几种方进行扩展 第一种:ES6提供的 Object.assign(); 第二种:ES5提供的 extend()方法 第三种:Object对象提供的 defineProperty( ...

  4. SqlServer2008 / SqlServer2012 禁用windows登录,sa忘记密码或密码过期如何登陆

    以管理员身份运行cmd 1.cmd 下  停止SqlServer服务,net stop mssqlserver: 2.新建windows账号test,加入administrators组里,授予管理员权 ...

  5. 数据结构与算法---排序算法(Sort Algorithm)

    排序算法的介绍 排序也称排序算法 (Sort Algorithm),排序是将一组数据,依指定的顺序进行排列的过程. 排序的分类 1) 内部排序: 指将需要处理的所有数据都加载 到内部存储器(内存)中进 ...

  6. js入门之内置数组对象 Array

    一. 数组 1. 创建数组的两种方式 1. 数组字面量 var array = [] 2. 数组的构造函数创建数组 var array = new Array(); 2. 如何判断一个变量是否是数组 ...

  7. EntityFramework进阶(一)- DbContext与ObjectContext互转

    本系列原创博客代码已在EntityFramework6.0.0测试通过,转载请标明出处 EF中我们常用的是DbContext作为上下文,如果要想获取元数据等信息还是要用到ObjectContext这个 ...

  8. Android笔记(八) Android中的布局——相对布局

    RelativeLayout又称为相对布局,也是一种常用的布局形式.和LinearLayout的排列规则不同,RelativeLayout显得更加随意一下,它通常通过相对定位 的方式让控件出现在布局的 ...

  9. Kafka 基本知识分享

    目录 一.基本术语 二.Kafka 基本命令 三.易混淆概念 四.Kafka的特性 五.Kafka的使用场景 六.Kakfa 的设计思想 七.Kafka 配置文件设置 八.新消费者 九.Kafka该怎 ...

  10. ajax二进制流乱码图片解决方法

    仅供自己参考 参考博客 在请求成功的地方 添加以下代码: var blob=new Blob(); blob=this.response; 既然二进制数据拿到了,那么要把它放在一个 html标签中,并 ...