【.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:/ ...
随机推荐
- python 之 前端开发( DOM操作)
11.47 DOM操作 查找节点: 11.471 直接查找 document.getElementById //根据ID获取唯一一个标签 document.getElementsByClassName ...
- Oracle 11g xe版本---总结1
一.创建用户和授予权限 1.1 环境: Oracle 11g xe 第三方图形客户端: PLSQL Windows 10 必须登录 HR 用户,下面的查询会使用到 HR 中的表. 1.2 SQL 语句 ...
- hadoop 伪分布启动-fs格式化
1.独立模式(standalone|local) nothing! 本地文件系统. 不需要启用单独进程. 2.pesudo(伪分布模式) 等同于完全分布式,只有一个节点. SSH: //(Socket ...
- spring的事务解决方案之@Transactional注解
首先此注解位于 org.springframework.transaction.annotation 这个包路径下面, 事务有两种类别,一种是编程式事务,另一种是声明式事务,显然此注解是声明式事务,这 ...
- vue+iview+mock模拟数据遍历
下载安装iview, 进入根目录,用命令行启动 npm install npm run build npm run dev 安装mock.js和axios npm install mock.js -s ...
- IDEA好用插件推荐
Maven Helper:排查maven依赖冲突神器,强力推荐! Alibaba Java Coding Guidelines:阿里巴巴编程规范 CamelCase:驼峰命名工具,SHIFT + AL ...
- oracle-3-Linux-11g安装-图形安装
在安装系统时就安装了图形桌面 参考博客地址:https://www.cnblogs.com/tibit/p/6134150.html 未参考,只是感觉不错:https://blog.csdn.net/ ...
- springboot + shiro 构建权限模块
权限模块基本流程 权限模块的基本流程:用户申请账号和权限 -->登陆认证 -->安全管控模块认证 -->调用具体权限模块(基于角色的权限控制) --> 登陆成功 -->访 ...
- snort_inline
snort_inline Link http://snort-inline.sourceforge.net/oldhome.html What is snort_inline? snort_inl ...
- PyCharm 占用过大 C 盘空间,system 配置文件迁移
随着 PyCharm 的持续使用,对应 C:\Users\<username>\.PyCharm<2018.3> 下的文件大小会持续增大,且通常为 system 文件夹下的内容 ...