开篇

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. ~json库的使用

    一.json简介 json全称"JavaScript Object Notation"(JavaScript对象表示法)它是一种基于文本,独立于语言的轻量级数据交换格式.易于让人阅 ...

  2. golang之格式化fmt.Printf

    当使用fmt包打印一个数值时,我们可以用%d.%o或%x参数控制输出的进制格式,就像下面的例子: o := 0666 fmt.Printf("%d %[1]o %#[1]o\n", ...

  3. Django model反向关联名称的方法(转)

    原文:https://www.jb51.net/article/152825.htm

  4. C#方法(用法,参数)

    方法:是一种用于实现可以由对象或类执行的计算或操作的成员,是一个已命名的语句集.方法就是把一些相关的语句组织到一起,用来执行一个任务的语句块.比如每个C#程序至少带一个main函数 1.格式:修饰符  ...

  5. hdu 2539 虽然是水题 wa了很多次 说明自己的基本功不扎实 需要打好基础先 少年

    两点吧 1.gets使用的时候 确保上一次的回车符对其没有影响 getline也是如此 这样的细节..  多注意啊!! 2.编写程序的时候 对一些极端的情况要多调试 比如此题当 n==1的时候..  ...

  6. TreeListView排序不对

    winForm控件TreeListView按照一定顺序后添加项,后发觉排序顺序自己变了,解决办法: TreeListViewItem viewItem = new TreeListViewItem() ...

  7. Visual Studio中找不到.Net Core SDK

    在win 7 64位上安装了.Net Core 2.1 x86 SDK后,又卸载重新安装了.Net Core 3/2 x64 SDK.结果在VS中新建项目时没有.Net Core 3.1 SDK. 在 ...

  8. axios使用API

    背景:请求失败后,因跨域引起的不能传递statusCode问题,通过设置前后台选项解决,这里先总结一下axios的使用 一.安装与配置: 安装: npm install axios axios使用AP ...

  9. 【SpringMVC】RESTful支持

    一.概述 1.1 什么是RESTful 1.2 URL的RESTful实现 二.演示 2.1 需求 2.2 第一步更改DispatcherServlet配置 2.3 第二步参数通过url传递 2.4 ...

  10. MySql 学习之 一条查询sql的执行过程

    相信大家都接触过Mysql数据库,而且也肯定都会写sql.我不知道大家有没有这样的感受,反正我是有过这样的想法.就是当我把一条sql语句写完了,并且执行完得到想要的结果.这时我就在想为什么我写这样的一 ...