上一章我們講了IRepository接口,這張我們來講IQuery
根據字面意思就可以知道,這次主要講數據查詢,上一章我們只針對單表做了查詢的操作,多表聯查並沒有實現
其實對於任何一個項目來說,多表聯查都是比較麻煩的地方,因為項目的“讀”操作,特別是多表的“讀”,至少占據所有“讀”的一半以上
然而至今,據我所知還沒有哪一款ORM工具可以靈活處理多表聯查;想要不寫sql語句,又想性能高,還想用強類型的ling查詢方法;這對於多表查詢來說比較難
鑒於此,也別做那些別扭的映射了(像NH),而如果用lingtosql我覺得還不如直接寫sql來的好;
是開發人員不可能不懂sql,那對多表查詢這一塊,干脆獨立一個Query類出來,專門處理這種事
好了這只是我的處理方式,我們來看看
IQuery.cs
1 public interface IQuery 2 { 3 T QuerySingle<T>(string sql, object paramPairs) where T : class; 4 IEnumerable<T> QueryList<T>(string sql, object paramPairs) where T : class; 5 6 /// <summary>必須帶上row_number() over({0}) RowNumber</summary> 7 Tuple<int, IEnumerable<T>> GetPage<T>(Page page, string sql, dynamic paramPairs = null) where T : class; 8 9 Tuple<int, IEnumerable<T>> GetPage<T>(string sql, object paramPairs = null) where T : class; 10 int Execute(string sql, dynamic paramPairs = null); 11 long Count(string sql, dynamic paramPairs = null); 12 }
上方法名就可以知道,寫sql,然后返回自定義的T或IEnumerable<T>
這里避免了用泛型類,因為某個實體大多數情況下可能也只是需要,上邊其中其中的1、2個而已
這里有一個Execute方法,其實不應該放在這的,但是也懶得寫另外一個類了,先放着吧
Query的實現
DapperQuery.cs
1 using Dapper; 2 using Dapper.Contrib.Extensions; 3 using LjrFramework.Common; 4 using LjrFramework.Interface; 5 using System; 6 using System.Collections.Generic; 7 using System.Data; 8 using System.Linq; 9 10 namespace LjrFramework.Data.Dapper 11 { 12 public class DapperQuery : IQuery 13 { 14 protected IDbConnection Conn { get; private set; } 15 16 public DapperQuery() 17 { 18 Conn = DbConnectionFactory.CreateDbConnection(); 19 } 20 21 public void SetDbConnection(IDbConnection conn) 22 { 23 Conn = conn; 24 } 25 26 public T QuerySingle<T>(string sql, object paramPairs) where T : class 27 { 28 return Conn.Query<T>(sql, paramPairs).SingleOrDefault(); 29 } 30 31 public IEnumerable<T> QueryList<T>(string sql, object paramPairs) where T : class 32 { 33 return Conn.Query<T>(sql, paramPairs); 34 } 35 36 /// <summary>自動分頁,必須帶上row_number() over({0}) RowNumber</summary> 37 public Tuple<int, IEnumerable<T>> GetPage<T>(Page page, string sql, object paramPairs = null) where T : class 38 { 39 var multi = Conn.GetPage<T>(page.PageIndex, page.PageSize, sql, paramPairs); 40 var count = multi.Read<int>().Single(); 41 var results = multi.Read<T>(); 42 return new Tuple<int, IEnumerable<T>>(count, results); 43 } 44 // 需自己實現分頁語句 45 public Tuple<int, IEnumerable<T>> GetPage<T>(string sql, object paramPairs = null) where T : class 46 { 47 var multi = Conn.GetGridReader<T>(sql, paramPairs); 48 var count = multi.Read<int>().Single(); 49 var results = multi.Read<T>(); 50 return new Tuple<int, IEnumerable<T>>(count, results); 51 } 52 53 54 public int Execute(string sql, object paramPairs = null) 55 { 56 return Conn.Execute(sql, paramPairs); 57 } 58 59 public long Count(string sql, object paramPairs = null) 60 { 61 return Conn.Query<long>(sql, paramPairs).SingleOrDefault(); 62 } 63 } 64 }
這個實現跟上一章差不多,都是直接調用Conn的擴展方法,
我們進去看看(public Tuple<int, IEnumerable<T>> GetPage<T>(string sql, object paramPairs = null) where T : class)的實現
可以看到dapper是已經支持sql語句的查詢,並且返回多個記錄(SqlMapper.GridReader)
每次分頁都要去手動刷選 頁數 與 記錄開始行數的話比較麻煩
所有我做了一點小改動,武學用戶寫分頁語句,直接查詢就可以了,后台會自動生成分頁語句的格式
不過要帶上row_number() over({0}) RowNumber;就是上邊那個有注釋的方法
他的實現如下
這樣用戶只需要准守一點約束,就會方便很多
這些都是在dapper的Extensions里實現的,用戶需要自行修改,自己想要的自定義的功能
好了,Query有效代碼寫完了,我們看看運行效果
Query測試
1 using Autofac; 2 using Company.Project.PO; 3 using LjrFramework.Data.Dapper; 4 using LjrFramework.Common; 5 using LjrFramework.Infrastructure; 6 using LjrFramework.Interface; 7 using Microsoft.VisualStudio.TestTools.UnitTesting; 8 using System; 9 using LjrFramework.Data.UnitOfWork; 10 11 namespace LjrFramework.UnitTest 12 { 13 [TestClass] 14 public class QueryTest 15 { 16 private IQuery query; 17 18 public QueryTest() 19 { 20 var builder = new ContainerBuilder(); 21 builder.RegisterType<DapperQuery>().As<IQuery>(); 22 23 var container = builder.Build(); 24 query = container.Resolve<IQuery>(); 25 26 } 27 28 [TestMethod] 29 public void QuerySingle() 30 { 31 var model = query.QuerySingle<LoginUser>("select * from LoginUser where Id = @Id", new { Id = "854B1FCA-F8D7-4B4B-AA5D-9075F1922721" }); 32 33 Assert.AreEqual(model.LoginName, "lanxiaoke-d318fd40-1b9d-42f8-a002-388b1228012d"); 34 } 35 36 [TestMethod] 37 public void QueryList() 38 { 39 var list = query.QueryList<LoginUser>("select * from LoginUser where LoginName like '%'+ @LoginName + '%'", new { LoginName = "lanxiaoke" }); 40 41 int index = 0; 42 foreach (var user in list) 43 { 44 index++; 45 } 46 47 Assert.AreEqual(index > 0, true); 48 } 49 50 [TestMethod] 51 public void GetPage() 52 { 53 var page = new Page() 54 { 55 PageIndex = 1, 56 PageSize = 10 57 }; 58 59 var results = query.GetPage<LoginUser>(page, 60 @"select row_number() over(order by CreateTime) RowNumber,* from LoginUser where LoginName like '%'+ @LoginName + '%'", new { LoginName = "lanxiaoke" }); 61 62 var total = results.Item1; 63 var list = results.Item2; 64 65 int index = 0; 66 foreach (var user in list) 67 { 68 index++; 69 } 70 71 Assert.AreEqual(index > 0, true); 72 } 73 74 [TestMethod] 75 public void GetPage2() 76 { 77 var page = new Page() 78 { 79 PageIndex = 1, 80 PageSize = 10 81 }; 82 83 var results = query.GetPage<LoginUser>( 84 @"select count(*) as TotalCount from LoginUser c where LoginName like '%'+ @LoginName + '%' 85 select row_number() over(order by CreateTime) RowNumber,* from LoginUser where LoginName like '%'+ @LoginName + '%'", 86 new { LoginName = "lanxiaoke" }); 87 88 var total = results.Item1; 89 var list = results.Item2; 90 91 int index = 0; 92 foreach (var user in list) 93 { 94 index++; 95 } 96 97 Assert.AreEqual(index > 0, true); 98 } 99 100 [TestMethod] 101 public void Count() 102 { 103 var row = query.Count("select count(*) from LoginUser"); 104 105 Assert.AreEqual(row > 1, true); 106 } 107 108 } 109 }
自此,多表查詢就講完了
項目架構開發系列
- 項目架構開發:數據訪問層之Cache
- 項目架構開發:數據訪問層之Logger
- 項目架構開發:數據訪問層之Repository
- 項目架構開發:數據訪問層之Query
- 項目架構開發:數據訪問層之UnitOfWork