数据访问层之Repository

 

接上文 项目架构开发:数据访问层之Logger

本章我们继续IRepository开发,这个仓储与领域模式里边的仓储有区别,更像一个工具类,也就是有些园友说的“伪仓储”,

这个仓储只实现单表的CURD与Query,都是通过主键ID或拉姆达表达式进行操作的,返回的都是单表的实体或实体集合,

多表的在IQuery接口中再讲;虽然如此,但是如果与“活动记录”开发模式搭配的话,会非常合适,可以减少开发的时间

及出错几率,更符合开发人员的类型调用习惯

IRepository.cs

 1     public interface IRepository<T> where T : class
2 {
3 void Add(T entity);
4 void AddBatch(IEnumerable<T> entitys);
5 void Update(T entity);
6 void Delete(T entity);
7 void Delete(string Id);
8 void Delete(int Id);
9 void Delete(Guid Id);
10 T Get(string Id);
11 T Get(Guid Id);
12 T Get(int Id);
13 T Get(T entity);
14 T Get(Expression<Func<T, bool>> func);
15 IEnumerable<T> GetAll();
16 IEnumerable<T> GetList(Expression<Func<T, bool>> where = null, Expression<Func<T, bool>> order = null);
17 Tuple<int, IEnumerable<T>> GetPage(Page page, Expression<Func<T, bool>> where = null, Expression<Func<T, bool>> order = null);
18 long Count(Expression<Func<T, bool>> where = null);
19 }

仓储的实现

这里我们只实现dapper的适配,EF有时间再搞吧

dapper大家应该都比较熟悉吧,不懂的朋友可以在园中搜索一下啊,很多案例

DapperRepository.cs

  1 using Dapper.Contrib.Extensions;
2 using LjrFramework.Common;
3 using LjrFramework.Interface;
4 using System;
5 using System.Collections.Generic;
6 using System.Data;
7 using System.Linq;
8 using System.Linq.Expressions;
9
10 namespace LjrFramework.Data.Dapper
11 {
12 public class DapperRepository<T> : IRepository<T> where T : class
13 {
14 protected IDbConnection Conn { get; private set; }
15
16 public DapperRepository()
17 {
18 Conn = DbConnectionFactory.CreateDbConnection();
19 }
20
21 public void SetDbConnection(IDbConnection conn)
22 {
23 Conn = conn;
24 }
25
26 public void Add(T entity)
27 {
28 Conn.Insert<T>(entity);
29 }
30
31 public void AddBatch(IEnumerable<T> entitys)
32 {
33 foreach (T entity in entitys)
34 {
35 Add(entity);
36 }
37 }
38
39 public void Update(T entity)
40 {
41 Conn.Update(entity);
42 }
43
44 public void Delete(T entity)
45 {
46 Conn.Delete(entity);
47 }
48
49 public void Delete(string Id)
50 {
51 var entity = Get(Id);
52 if (entity == null) return;
53
54 Delete(entity);
55 }
56
57 public void Delete(int Id)
58 {
59 var entity = Get(Id);
60 if (entity == null) return;
61
62 Delete(entity);
63 }
64 public void Delete(Guid Id)
65 {
66 var entity = Get(Id);
67 if (entity == null) return;
68
69 Delete(entity);
70 }
71
72 public T Get(T entity)
73 {
74 return Conn.Get<T>(entity);
75 }
76
77 public T Get(Guid Id)
78 {
79 return Conn.Get<T>(Id);
80 }
81
82 public T Get(string Id)
83 {
84 return Conn.Get<T>(Id);
85 }
86
87 public T Get(int Id)
88 {
89 return Conn.Get<T>(Id);
90 }
91
92 public T Get(Expression<Func<T, bool>> func)
93 {
94 var linqToWhere = new LinqToWhere<T>();
95 linqToWhere.Parse(func);
96
97 return Conn.GetByFunc<T>(linqToWhere.Where, linqToWhere.KeyValuePairs);
98 }
99
100 public IEnumerable<T> GetAll()
101 {
102 return Conn.GetAll<T>();
103 }
104
105 public IEnumerable<T> GetList(Expression<Func<T, bool>> where = null, Expression<Func<T, bool>> order = null)
106 {
107 where = where.And(order);
108
109 var linqToWhere = new LinqToWhere<T>();
110 linqToWhere.Parse(where);
111
112 return Conn.GetListByFunc<T>(linqToWhere.Where, linqToWhere.KeyValuePairs);
113 }
114
115 public Tuple<int, IEnumerable<T>> GetPage(Page page, Expression<Func<T, bool>> where = null, Expression<Func<T, bool>> order = null)
116 {
117 where = where.And(order);
118
119 var linqToWhere = new LinqToWhere<T>();
120 linqToWhere.Parse(where);
121
122 var multi = Conn.GetPage<T>(page.PageIndex, page.PageSize, linqToWhere.Order, linqToWhere.Where, linqToWhere.KeyValuePairs);
123 var count = multi.Read<int>().Single();
124 var results = multi.Read<T>();
125
126 return new Tuple<int, IEnumerable<T>>(count, results);
127 }
128
129 public long Count(Expression<Func<T, bool>> where = null)
130 {
131 var linqToWhere = new LinqToWhere<T>();
132 linqToWhere.Parse(where);
133
134 return Conn.Count<T>(linqToWhere.Where, linqToWhere.KeyValuePairs);
135 }
136 }
137 }

注意标红的那行,Conn的所有方法都是在命名空间(Dapper.Contrib.Extensions)下的扩展方法

我们看看其中的Insert实现方式,为什么直接传递T就可以,而不用写sql语句

可以看到,dapper后台是遍历实体的属性,最后也是拼凑成符合格式的sql语句;

这一点也可以自己扩展,有很大的便利性,所以他写在Extensions中

DbConnectionFactory.cs 也很简单,是dapper支持多数据库的工厂类

 1 public class DbConnectionFactory
2 {
3 private static readonly string connectionString;
4 private static readonly string databaseType;
5
6 static DbConnectionFactory()
7 {
8 var collection = ConfigurationManager.ConnectionStrings["connectionString"];
9 connectionString = collection.ConnectionString;
10 databaseType = collection.ProviderName.ToLower();
11 }
12
13 public static IDbConnection CreateDbConnection()
14 {
15 IDbConnection connection = null;
16 switch (databaseType)
17 {
18 case "system.data.sqlclient":
19 connection = new System.Data.SqlClient.SqlConnection(connectionString);
20 break;
21 case "mysql":
22 //connection = new MySql.Data.MySqlClient.MySqlConnection(connectionString);
23 break;
24 case "oracle":
25 //connection = new Oracle.DataAccess.Client.OracleConnection(connectionString);
26 //connection = new System.Data.OracleClient.OracleConnection(connectionString);
27 break;
28 case "db2":
29 connection = new System.Data.OleDb.OleDbConnection(connectionString);
30 break;
31 default:
32 connection = new System.Data.SqlClient.SqlConnection(connectionString);
33 break;
34 }
35 return connection;
36 }
37 }

自此,dapper适配的仓储就完成了

我们在测试项目中看看效果,这里我们不在继续在基础设施里添加仓储了,用另一种方式:IOC

项目引用Autofac,用依赖出入来初始化IRepository<T>接口

测试仓储功能

 1 [TestClass]
2 public class DapperRepositoryTest
3 {
4 private IRepository<LoginUser> repository;
5
6 public DapperRepositoryTest()
7 {
8 var builder = new ContainerBuilder();
9 builder.RegisterType<DapperRepository<LoginUser>>().As<IRepository<LoginUser>>();
10
11 var container = builder.Build();
12 repository = container.Resolve<IRepository<LoginUser>>();
13 }
14
15 [TestMethod]
16 public void Add()
17 {
18 var loginUser = new LoginUser()
19 {
20 Id = Guid.NewGuid(),
21 LoginName = "lanxiaoke-" + Guid.NewGuid().ToString(),
22 Password = "mima1987",
23 IsEnabled = 1,
24 CreateTime = DateTime.Now
25 };
26
27 repository.Add(loginUser);
28
29 long count = repository.Count(t => t.LoginName == loginUser.LoginName);
30
31 Assert.AreEqual(true, count == 1);
32 }
33
34 [TestMethod]
35 public void Get()
36 {
37 var loginUser = new LoginUser()
38 {
39 Id = Guid.NewGuid(),
40 LoginName = "lanxiaoke-" + Guid.NewGuid().ToString(),
41 Password = "mima1987",
42 IsEnabled = 1,
43 CreateTime = DateTime.Now
44 };
45 repository.Add(loginUser);
46
47 var tmp = repository.Get(loginUser.Id);
48 Assert.AreEqual(loginUser.Id, tmp.Id);
49
50 var tmp2 = repository.Get(w => w.Id == loginUser.Id && w.IsEnabled == loginUser.IsEnabled);
51 Assert.AreEqual(loginUser.Id, tmp2.Id);
52 }
53 ...//限于篇幅,只写这么多了,大部分代码都差不多
54 }

注意这句:container.Resolve<IRepository<LoginUser>>(); 这句就是实现初始化IRepository<T>接口;

如何初始化呢?看上一句:builder.RegisterType<DapperRepository<LoginUser>>().As<IRepository<LoginUser>>(); 直接注册DapperRepository就可以了

其实这里也可以用配置的方式初始化IRepository<T>,这样就可以避免DapperRepository<T>与业务层耦合了

测试项目,我们就暂且这么写吧。

我们来看看效果

下边都是这次测试生成的数据

自此 IRepository 就开发完成了

项目架构开发系列

 
分类: 架构设计

数据访问层之Repository的更多相关文章

  1. 项目架构开发:数据访问层之Repository

    接上文 项目架构开发:数据访问层之Logger 本章我们继续IRepository开发,这个仓储与领域模式里边的仓储有区别,更像一个工具类,也就是有些园友说的“伪仓储”, 这个仓储只实现单表的CURD ...

  2. 项目架构开发:数据访问层之Cache

    数据访问层简单介绍 数据访问层,提供整个项目的数据访问与持久化功能.在分层系统中所有有关数据访问.检索.持久化的任务,最终都将在这一层完成. 来看一个比较经典的数据访问层结构图 大概可以看出如下信息 ...

  3. 项目架构开发:数据访问层之Logger

    接上文 项目架构开发:数据访问层之Cache 本章我们继续ILogger的开发 ILogger.cs public interface ILogger { void Info(object messa ...

  4. 项目架构开发:数据访问层之UnitOfWork

    接上文 项目架构开发:数据访问层之IQuery 本章我们继续IUnitOfWork的开发,从之前的IRepository接口中就可以看出,我们并没有处理单元事务, 数据CUD每次都是立即执行的,这样有 ...

  5. 项目架构开发:数据访问层之Query

    接上文 项目架构开发:数据访问层之Repository 上一章我们讲了IRepository接口,这张我们来讲IQuery 根据字面意思就可以知道,这次主要讲数据查询,上一章我们只针对单表做了查询的操 ...

  6. 数据访问模式之Repository模式

    数据访问模式之Repository模式   数据访问层无非就是对数据进行增删改查,其中增.删.改等我们可以抽象出来写一个公共的接口或抽象类来定义这些方法,并采用一个基类实现这些方法,这样该基类派生的子 ...

  7. ClownFish:比手写代码还快的通用数据访问层

    http://www.cnblogs.com/fish-li/archive/2012/07/17/ClownFish.html 阅读目录 开始 ClownFish是什么? 比手写代码还快的执行速度 ...

  8. 使用JDBC构建简单的数据访问层

    本教程的目的是使用Java编写的分离的层去访问数据库中的表,这一层通常称为数据访问层(DAL) 使用DAL的最大好处是通过直接使用一些类似insert()和find()的方法简化了数据库的访问操作,而 ...

  9. 使用Ninject+Moq在单元测试中抽象数据访问层

    一.测试方法的业务逻辑时,通常都需要从数据库读取测试数据,但是每次初始化数据库数据都很麻烦,也会影响到其它业务对数据的访问,怎样抽象数据访问层呢?就是用Moq去模拟数据访问的逻辑     二.步骤如下 ...

随机推荐

  1. Java基础学习总结(51)——JAVA分层理解

    service是业务层  action层即作为控制器 DAO (Data Access Object) 数据访问   1.JAVA中Action层, Service层 ,modle层 和 Dao层的功 ...

  2. 开发板 视频1 05_01 05_02 05_03 关于ubuntu的一些操作

    ctrl+alt+T 打开中端 ctrl+d  退出 ctrl+alt+f1 到f6 进入dos中端 ctrl+alt+f7 是退出 05_02 启动root用户   也就是进入 前面出现root了 ...

  3. 8.3 Android灯光系统_编写HAL_lights.c

    注意在led-classes.c中定义的led_class_attrs[]所建立的文件的属性应该改为0666,否则应用程序无权操作它 同时ledtrig-time.c里面对应新建的那几个delay_o ...

  4. [RxJS] Replace zip with combineLatest when combining sources of data

    This lesson will highlight the true purpose of the zip operator, and how uncommon its use cases are. ...

  5. 字典(dictionary)的设计

    1. 简单接口 struct Dict{ bool has(const string& key); void insert(const string& key, const strin ...

  6. SpringBoot 使用 @Value 从 YAML文件读取属性(转)

    在 YAML中有如下配置 paypal: mode:live 在类中,通过 @Value属性读取 @Value("${paypal.mode}") private String m ...

  7. JDBC之一:JDBC快速入门 分类: B1_JAVA 2014-02-19 14:49 745人阅读 评论(0) 收藏

      (1)下载Oracle的JDBC驱动,一般放在$ORACLE_HOME/jdbc/lib目录,关于驱动的版本请见: http://elf8848.iteye.com/blog/811037     ...

  8. Objective-C中 ==、isEqual、isEqualToString判断字符串相等

    图片发自简书App 在判断一个字符串类型的变量是否与某字符时相等,你可能写下这样一行代码 if (activityType == @"0"){} //activityType是某一 ...

  9. jquery-10 js加载的时机如何选择

    jquery-10 js加载的时机如何选择 一.总结 一句话总结:主要应用widow的ready()方法和load()方法. 1.内部文件中DOM加载完毕执行js如何书写? 把js标签放在body之后 ...

  10. 使用truss、strace或ltrace诊断软件的"疑难杂症"

    原文链接 简介 进程无法启动,软件运行速度突然变慢,程序的"Segment Fault"等等都是让每个Unix系统用户头痛的问题,本文通过三个实际案例演示如何使用truss.str ...