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

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

上一章我们讲了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 }

自此,多表查询就讲完了

项目架构开发系列

时间: 2024-12-26 19:24:55

项目架构开发:数据访问层之Query的相关文章

企业级应用框架(二)三层架构之数据访问层的封装与抽象

接上一篇我们来对数据访问层进行封装与抽象.在上一篇我们知道,要解除BLL对DAL的依赖,我们就必须抽象出DAL层的接口,同时基于DAL的数据访问技术很多,如EF,ADO.NET,LINQ TO SQL,因此,我们的数据访问层必须对这些技术提供相应的支持.所以今天我们要做的事情有两件,第一,定义我们的数据访问层接口:第二,屏蔽各类数据库访问技术的差异,提供统一的数据库访问模型.举个例子,我们只需要修改一下我们的配置文件,就能够把ADO.NET的实现方式,改变成EF的实现方式.好下面搭建我们的三层构

企业级应用框架(三)三层架构之数据访问层的改进以及测试DOM的发布

在上一篇我们在宏观概要上对DAL层进行了封装与抽象.我们的目的主要有两个:第一,解除BLL层对DAL层的依赖,这一点我们通过定义接口做到了:第二,使我们的DAL层能够支持一切数据访问技术,如Ado.net,EF,linq To Sql,这一点我们实现的不是很完美,仍有很大的改进空间,本文将加以改进. 在此之前我们来看一下我们最新的dom(PS:经过两天的赶工,我们的dom已经相对成熟,其中BLL层已经被我高度抽象化了,并且引进了业务上文文的概念:DAL层除了具体的技术实现尚为完成,其他方面已经相

关于面对对象过程中的三大架构以及数据访问层(实体类、数据操作类)

面向对象开发项目三层架构: 界面层.业务逻辑层.数据访问层 数据访问层,分为实体类和数据访问类 在项目的下面添加一个App_Code文件夹把所有的类放在App_Code这个文件夹下边. 一.实体类 数据库中的表映射为一个类,类名与表名一致.表中的每一列,都为该类下的成员变量和属性也就是最简单的封装 把数据库中的表名变为类的类名. 把数据库中的每一个列,变为实体类中的成员变量和属性(也就是对每个数据库中的字段封装) 列名与属性名一致.成员变量名:在列名前边加上下划线.因为在外部访问只能访问到属性,

随机获得MySQL数据库中100条数据方法 驾照题库项目 MVC架构 biz业务层的实现类 根据考试类型rand或order通过dao数据访问层接口得到数据库中100或全部数据

package com.swift.jztk.biz; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Random; import com.google.gson.Gson; import com.swift.jztk.bean.Result

数据访问层之Repository

数据访问层之Repository 接上文 项目架构开发:数据访问层之Logger 本章我们继续IRepository开发,这个仓储与领域模式里边的仓储有区别,更像一个工具类,也就是有些园友说的"伪仓储", 这个仓储只实现单表的CURD与Query,都是通过主键ID或拉姆达表达式进行操作的,返回的都是单表的实体或实体集合, 多表的在IQuery接口中再讲:虽然如此,但是如果与"活动记录"开发模式搭配的话,会非常合适,可以减少开发的时间 及出错几率,更符合开发人员的类型

项目架构开发:异常处理及日志

上一篇我们完善了多层开发的效率问题,传送门:项目架构开发:展现层(下) 这次我们完成架构的异常处理功能,异常处理一般都与日志分不开的,因为分析及定位问题需要一些详细信息: 稍微正规一点的公司,都会分开发.测试及生产环境.在本地及测试环境出BUG了,问题很好解决 调试跟踪问题,三下五除二就搞完了:但是在生产环境出问题,基本上是不允许直连数据库调试的: 这时候如何没有足够的异常信息参考,那你就悲催了,你等着加班熬夜吧. 为了解决这个问题,所以异常信息的捕捉及记录就显得非常重要了,一个完善的系统,出问

asp.net-wingtip学习之创建数据访问层

一. 什么是数据访问层在wingtip项目中,数据访问层是对以下三者的总称:1. product类等数据相关的类(class)2. 数据库和存储类成员的数据表(database)3. 上述二者的交互操作. product类: 1 using System.ComponentModel.DataAnnotations; 2 3 namespace WingtipToys.Models 4 { 5 public class Product 6 { 7 [ScaffoldColumn(false)]

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

前边我们构建了个数据访问层,功能虽然简单,但是基本够用了.传送门:项目架构开发:数据访问层 这次我们构建业务逻辑层 业务逻辑是一个项目.产品的核心,也是现实世界某种工作流程在代码层面的体现. 所以,业务逻辑的合理组织构造,或更真实地反映现实业务操作,对项目的成功与否非常重要 现在业界对业务逻辑层的开发,一般会参考Martin Fowler大师提出来的针对业务层开发的四种模式 分别是面向过程的事务脚本.表模块模式,面向对象的活动记录与领域开发模式 我们要做的就是领域驱动开发模式,注意标题中的“失血

【2017-04-20】Ado.Net与面向对象结合架构中的数据访问层(实体类,数据访问类)

开发项目三层架构:界面层.业务逻辑层.数据访问层 今天学习一下数据访问层,分为实体类和数据访问类 所有的类放在App_Code这个文件夹下边.养成一个好的习惯. 一.实体类 数据库中的表映射为一个类,类名与表名一致.表中的每一列,都为该类下的成员变量和属性也就是最简单的封装 把数据库中的表名变为类的类名. 把数据库中的每一个列,变为实体类中的成员变量和属性 列名与属性名一致.成员变量名:在列名前边加上下划线.因为在外部访问只能访问到属性,为了看起来一致. using System; using