开篇

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. vagrant root 登录虚拟机

    这个问题本来觉得是个特别简单的问题,昨天弄的时候折腾了半晚上.所以打算记录下过程,主要也被网上的各种信息误导了. 1 先看下我这vagrant配置信息 Vagrant.configure(" ...

  2. linux安装png2icon方法

    此工具用于将png图片转换为ico格式的文件,一个小工具,但很实用 官网:http://www.winterdrache.de/freeware/png2ico/ 下载: wget http://ww ...

  3. 解决阿里云OSS The bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint的办法

    以前有一个上海节点的存储包,一直使用正常.最近购买了一个全国的存储包,发现在上传文件的时候有这个问题. 尝试了很多办法,还提交了工单,都没有解决. 最后解决办法如下: 1.在阿里云OSS管理控制台下, ...

  4. ip地址 与子网掩码 的计算

    ip地址 与子网掩码 的计算 128.0.0.0=1 192.0.0.0=2224.0.0.0=3 240.0.0.0=4 248.0.0.0=5 252.0.0.0=6 254.0.0.0=7 25 ...

  5. R_基础_01

    R语言介绍:R是一种区分大小写的解释型语言.R中有多种数据类型,包括向量.矩阵.数据框(与数据集类似)以及列表(各种对象的集合),广泛用于数据统计. R的特点:一次交互式会话期间的所有数据对象都被保存 ...

  6. 【转载】C#使用as关键字将对象转换为指定类型

    在C#的编程开发过程中,很多时候涉及到数据类型的转换,可使用强制转换的方式,不过强制转换数据类型有时候会抛出程序异常错误,可以使用as关键字来进行类型的转换,如果转换成功将返回转换后的对象,如果转换不 ...

  7. java读取文件的几种方式性能比较

    //普通输入流读取文件内容 public static long checksumInputStream(Path filename) { try(InputStream in= Files.newI ...

  8. ios获取数组中的最大值

    在编码过程中,我们通常碰到一组数据,需要自己简单的处理下,拿到数组中的总和,大小和平均值数据. 1.简单粗暴的方法,快速求和. NSArray * array = @[@"35", ...

  9. awk 常用选项及数组的用法和模拟生产环境数据统计

    awk 常用选项总结 在 awk 中使用外部的环境变量 (-v) awk -v num2="$num1" -v var1="$var" 'BEGIN{print ...

  10. NTFS文件系统概述

    NTFS简介 NTFS是Windows NT家族1的限制级专用的文件系统2.Win95.Win98识别不了NTFS,只有支持NT内核的OS才能识别NTFS文件系统.当前,NTFS取代了老式的FAT文件 ...