天天看點

資料通路層之Repository

接上文 項目架構開發:資料通路層之Logger

資料通路層之Repository

本章我們繼續IRepository開發,這個倉儲與領域模式裡邊的倉儲有差別,更像一個工具類,也就是有些園友說的“僞倉儲”,

這個倉儲隻實作單表的CURD與Query,都是通過主鍵ID或拉姆達表達式進行操作的,傳回的都是單表的實體或實體集合,

多表的在IQuery接口中再講;雖然如此,但是如果與“活動記錄”開發模式搭配的話,會非常合适,可以減少開發的時間

及出錯幾率,更符合開發人員的類型調用習慣

IRepository.cs

資料通路層之Repository

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     }      
資料通路層之Repository

倉儲的實作

資料通路層之Repository
資料通路層之Repository

這裡我們隻實作dapper的适配,EF有時間再搞吧

dapper大家應該都比較熟悉吧,不懂的朋友可以在園中搜尋一下啊,很多案例

DapperRepository.cs

資料通路層之Repository
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 }      
資料通路層之Repository

注意标紅的那行,Conn的所有方法都是在命名空間(Dapper.Contrib.Extensions)下的擴充方法

我們看看其中的Insert實作方式,為什麼直接傳遞T就可以,而不用寫sql語句

資料通路層之Repository

可以看到,dapper背景是周遊實體的屬性,最後也是拼湊成符合格式的sql語句;

這一點也可以自己擴充,有很大的便利性,是以他寫在Extensions中

DbConnectionFactory.cs 也很簡單,是dapper支援多資料庫的工廠類

資料通路層之Repository
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     }      
資料通路層之Repository

自此,dapper适配的倉儲就完成了

我們在測試項目中看看效果,這裡我們不在繼續在基礎設施裡添加倉儲了,用另一種方式:IOC

項目引用Autofac,用依賴出入來初始化IRepository<T>接口

測試倉儲功能

資料通路層之Repository
資料通路層之Repository
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     }      
資料通路層之Repository

注意這句:container.Resolve<IRepository<LoginUser>>(); 這句就是實作初始化IRepository<T>接口;

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

其實這裡也可以用配置的方式初始化IRepository<T>,這樣就可以避免DapperRepository<T>與業務層耦合了

測試項目,我們就暫且這麼寫吧。

我們來看看效果

資料通路層之Repository

下邊都是這次測試生成的資料

資料通路層之Repository

自此 IRepository 就開發完成了

項目架構開發系列

  • 項目架構開發:資料通路層之Cache
  • 項目架構開發:資料通路層之Logger
  • 項目架構開發:資料通路層之Repository
  • 項目架構開發:資料通路層之Query
  • 項目架構開發:資料通路層之UnitOfWork

分類: 架構設計