【.Net设计模式系列】仓储(Repository)模式 ( 一 )
开篇
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)模式 ( 一 )的更多相关文章
- Android设计模式系列--工厂方法模式
工厂方法模式,往往是设计模式初学者入门的模式,的确,有人称之为最为典型最具启发效果的模式.android中用到了太多的工厂类,其中有用工厂方法模式的,当然也有很多工厂并不是使用工厂方法模式的,只是工具 ...
- [js高手之路]设计模式系列课程-组合模式+寄生组合继承实战新闻列表
所谓组合模式,就是把一堆结构分解出来,组成在一起,现实中很多这样的例子,如: 1.肯德基套餐就是一种组合模式, 比如鸡腿堡套餐,一般是是由一个鸡腿堡,一包薯条,一杯可乐等组成的 2.组装的台式机同理, ...
- Java设计模式系列-抽象工厂模式
原创文章,转载请标注出处:https://www.cnblogs.com/V1haoge/p/10755412.html 一.概述 抽象工厂模式是对工厂方法模式的再升级,但是二者面对的场景稍显差别. ...
- Java设计模式系列-工厂方法模式
原创文章,转载请标注出处:<Java设计模式系列-工厂方法模式> 一.概述 工厂,就是生产产品的地方. 在Java设计模式中使用工厂的概念,那就是生成对象的地方了. 本来直接就能创建的对象 ...
- Java设计模式系列-装饰器模式
原创文章,转载请标注出处:<Java设计模式系列-装饰器模式> 一.概述 装饰器模式作用是针对目标方法进行增强,提供新的功能或者额外的功能. 不同于适配器模式和桥接模式,装饰器模式涉及的是 ...
- 设计模式系列之迭代器模式(Iterator Pattern)——遍历聚合对象中的元素
模式概述 模式定义 模式结构图 模式伪代码 模式改进 模式应用 模式在JDK中的应用 模式在开源项目中的应用 模式总结 说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修 ...
- 设计模式系列之建造者模式(Builder Pattern)——复杂对象的组装与创建
说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...
- 设计模式系列之工厂模式三兄弟(Factory Pattern)
说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...
- 设计模式系列之组合模式(Composite Pattern)——树形结构的处理
说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...
随机推荐
- 面试题之web访问突然延迟问题
前言 面试官经常会问平时访问正常的网页突然变慢是什么原因引起的,说明下你排查的思路:我认为这种问题很能考察一个人的综合知识面,既能融通的贯彻知识点,也能展看对每个知识点进行详细的考问. 下面我按我自己 ...
- Linux和Windows系统目录结构区别
Windows目录结构图 Linux目录结构图 我们所有的操作尽量都要在/home/username目录下进行. 快捷进入家目录方式是cd ~.
- Python开发【第二章】:模块和运算符
一.模块初识: Python有大量的模块,从而使得开发Python程序非常简洁.类库有包括三中: Python内部提供的模块 业内开源的模块 程序员自己开发的模块 1.Python内部提供一个 sys ...
- JDBC连接池的testQuery/validationQuery设置
在<Tomcat中使用Connector/J连接MySQL的超时问题>帖子中想要增加对连接池中连接的测试/验证,防止数据库认为连接已死而Web应用服务器认为连接还有效的问题,Mysql文档 ...
- MySQL 体系结构及存储引擎
MySQL 原理篇 MySQL 索引机制 MySQL 体系结构及存储引擎 MySQL 语句执行过程详解 MySQL 执行计划详解 MySQL InnoDB 缓冲池 MySQL InnoDB 事务 My ...
- springmvc+mybatis的增删改查入门
先到官网了解mybatis的语法:https://mybatis.org/mybatis-3/zh/sqlmap-xml.html 前端用了thymeleaf和vue.js,效果图和demo地址:ht ...
- VBA Exit Do语句
当想要根据特定标准退出Do循环时,可使用Exit Do语句. 它可以同时用于Do...While和Do...Until直到循环. 当Exit Do被执行时,控制器在Do循环之后立即跳转到下一个语句. ...
- css 垂直方向 margin 边距 重合
1:控制两个相邻边盒子之间的距离,在A或者B盒子上用margin控制,就可以控制距离了. 2:父子级之间的元素,常规文档流中,只要垂直外边距直接接触就会发生合并.比如在写header标签时,想移动he ...
- element-ui中使用表单验证的问题
<el-form ref="ruleRules" :inline="true" :model="ruleInfo"> <e ...
- 前端之:传统的DOM是如何渲染的?
a.纯后端渲染:页面发送请求,后端服务器中将数据拼成完整DOM树,并转换成一个字节流作为HTTP Response的body返回给浏览器.优点在于 返回的HTTP Response是包含着全部页面内容 ...