数据访问层之Repository

Posted Leo_wlCnBlogs

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据访问层之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的主要内容,如果未能解决你的问题,请参考以下文章

PetShop数据访问层之数据库访问设计 - 《解剖PetShop》系列之二

PetShop数据访问层之消息处理 - 《解剖PetShop》系列之三

项目架构开发:业务逻辑层之领域驱动失血模型

What's the difference between @Component, @Repository & @Service annotations in Spring?(代码片段

springboot整合视图层之freemarker

计算机网络——数据链路层之MAC子层