最近在弄一个东东,类似那种CMS的后台管理系统,方便作为其它项目的初始化框架用的。

现在遇到个问题,如标题所示:Dapper通用的多表联合分页查询怎么破?

单表的话很简单就可以实现,多表不通用的话也可以很方便的实现,那么如果多表通用的话,怎么办呢?

难道只能通过拼接sql或者使用存储过程吗?我先来展示下我的实现方式,希望你有更好的方式,然后同我分享一下,以便解决我的困扰。

因为本来就是做的传统的CMS类似的项目,所以技术选型也是比较传统,抛弃了mvvm的js框架、webapi接口、以及nosql缓存。

技术选型:MVC5、Mysql、Dapper、Autofac、Layui、阿里巴巴矢量库、T4(后面补上)。

  • MVC5:目前.net开发的主流web框架。
  • Mysql:轻量免费功能强大的关系型数据库。
  • Dapper:据说是性能最好的.net ORM框架。
  • Autofac:据说是性能最好的.net IOC框架。
  • Layui:经典的模块化UI框架,还是很适合我们这样的后端开发人员的。
  • 阿里巴巴矢量库:丰富的矢量图标库。
  • T4:强大的代码生成模板。

我选择的都是轻量级比较干净的东东来组合的框架。

我选择由外入内的方式来阐述我现在遇到的问题。以用户管理界面为例,我讲只列出涉及到用户分页查询的代码,将会省略其它代码.....

大致上的效果如下图所示:

经典的多层架构

Global.asax.cs代码,Dapper自动注入。

  public class MvcApplication : System.Web.HttpApplication{protected void Application_Start(){AreaRegistration.RegisterAllAreas();FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);RouteConfig.RegisterRoutes(RouteTable.Routes);BundleConfig.RegisterBundles(BundleTable.Bundles);//创建autofac管理注册类的容器实例var builder = new ContainerBuilder();SetupResolveRules(builder);//使用Autofac提供的RegisterControllers扩展方法来对程序集中所有的Controller一次性的完成注册 支持属性注入
            builder.RegisterControllers(Assembly.GetExecutingAssembly()).PropertiesAutowired();        // 把容器装入到微软默认的依赖注入容器中var container = builder.Build();DependencyResolver.SetResolver(new AutofacDependencyResolver(container));}private static void SetupResolveRules(ContainerBuilder builder){//WebAPI只用引用services和repository的接口,不用引用实现的dll。//如需加载实现的程序集,将dll拷贝到bin目录下即可,不用引用dllvar iServices = Assembly.Load("RightControl.IService");var services = Assembly.Load("RightControl.Service");var iRepository = Assembly.Load("RightControl.IRepository");var repository = Assembly.Load("RightControl.Repository");//根据名称约定(服务层的接口和实现均以Services结尾),实现服务接口和服务实现的依赖
            builder.RegisterAssemblyTypes(iServices, services).Where(t => t.Name.EndsWith("Service")).AsImplementedInterfaces().PropertiesAutowired();//根据名称约定(数据访问层的接口和实现均以Repository结尾),实现数据访问接口和数据访问实现的依赖
            builder.RegisterAssemblyTypes(iRepository, repository).Where(t => t.Name.EndsWith("Repository")).AsImplementedInterfaces().PropertiesAutowired();}}

BaseController:

   public class BaseController : Controller{// GET: Basepublic virtual ActionResult Index(){return View();}

UserController:

    public class UserController : BaseController{private IUserService service;public UserController(IUserService _service){service = _service;}/// <summary>/// 加载数据列表/// </summary>/// <param name="pageInfo">页面实体信息</param>/// <param name="filter">查询条件</param>/// <returns></returns>
        [HttpGet]public JsonResult List(PageInfo pageInfo, UserModel filter){var result = service.GetListByFilter(filter, pageInfo);return Json(result, JsonRequestBehavior.AllowGet);}

PageInfo:

    public class PageInfo{public int page { get; set; }public int limit { get; set; }/// <summary>/// 排序字段 CreateOn/// </summary>public string field { get; set; }/// <summary>/// 排序方式 asc desc/// </summary>public string order { get; set; }/// <summary>/// 返回字段逗号分隔/// </summary>public string returnFields { get; set; }public string prefix { get; set; }}

View Code

UserModel:

using DapperExtensions;
using System;
using System.ComponentModel.DataAnnotations;namespace RightControl.Model
{[Table("t_User")]public class UserModel:Entity{/// <summary>/// 用户名/// </summary>[Display(Name = "用户名")]public string UserName { get; set; }/// <summary>/// 真实名称/// </summary>[Display(Name = "真实名称")]public string RealName { get; set; }/// <summary>/// 密码/// </summary>public string PassWord { get; set; }/// <summary>/// 创建者/// </summary>public int CreateBy { get; set; }/// <summary>/// 角色ID/// </summary>public int RoleId { get; set; }/// <summary>/// 更新时间/// </summary>[Display(Name = "更新时间")]public DateTime UpdateOn { get; set; }[Computed]public string RoleName { get; set; }}
}

View Code

Entity:

    public class Entity{[DapperExtensions.Key(true)]public virtual int Id { get; set; }/// <summary>/// 创建时间/// </summary>
        [DataType(DataType.Date)][DisplayFormat(DataFormatString = "{0:yyyy-MM-dd HH:mm:ss}")][Display(Name = "创建时间")]public DateTime CreateOn { get; set; }/// <summary>/// 菜单状态(1:启用,0:禁用)/// </summary>public bool Status { get; set; }#region 查询条件[Computed]public string StartEndDate { get; set; }#endregion}

IBaseService:

    public interface IBaseService<T> where T : class, new(){dynamic GetListByFilter(T filter, PageInfo pageInfo);}

IUserService:

    public interface IUserService : IBaseService<UserModel>{...}

BaseService:

    public abstract class BaseService<T> where T : class, new(){public IBaseRepository<T> baseRepository{get; set;}
public dynamic GetPageUnite(IBaseRepository<T> repository, PageInfo pageInfo, string where, object filter){string _orderBy = string.Empty;if (!string.IsNullOrEmpty(pageInfo.field)){_orderBy = string.Format(" ORDER BY {0} {1}", pageInfo.prefix+pageInfo.field, pageInfo.order);}else{_orderBy = string.Format(" ORDER BY {0}CreateOn desc",pageInfo.prefix);}long total = 0;var list = repository.GetByPageUnite(new SearchFilter { pageIndex = pageInfo.page, pageSize = pageInfo.limit, returnFields = pageInfo.returnFields, param = filter, where = where, orderBy = _orderBy }, out total);return Pager.Paging(list, total);}protected  string CreateWhereStr(Entity filter, string _where){if (!string.IsNullOrEmpty(filter.StartEndDate) && filter.StartEndDate != " ~ "){var dts = filter.StartEndDate.Trim().Split('~');var start = dts[0].Trim();var end = dts[1].Trim();if (!string.IsNullOrEmpty(start)){_where += string.Format(" and CreateOn>='{0}'", start + " 00:00");}if (!string.IsNullOrEmpty(end)){_where += string.Format(" and CreateOn<='{0}'", end + " 59:59");}}return _where;}}

UserService:

    public class UserService: BaseService<UserModel>, IUserService{public IUserRepository repository { get; set; }//属性注入public dynamic GetListByFilter(UserModel filter, PageInfo pageInfo){pageInfo.prefix = "u.";string _where = " t_User u INNER JOIN t_role r on u.RoleId=r.Id";if (!string.IsNullOrEmpty(filter.UserName)){_where += string.Format(" and {0}UserName=@UserName",pageInfo.prefix);}if (!string.IsNullOrEmpty(pageInfo.order)){pageInfo.order = pageInfo.prefix + pageInfo.order;}pageInfo.returnFields = string.Format("{0}Id,{0}UserName,{0}RealName,{0}CreateOn,{0}`PassWord`,{0}`Status`,{0}RoleId,r.RoleName",pageInfo.prefix);return GetPageUnite(baseRepository, pageInfo, _where, filter);}

IBaseRepository:

 public interface IBaseRepository<T> where T : class, new(){IEnumerable<T> GetByPageUnite(SearchFilter filter, out long total);}

IUserRepository:

    public interface IUserRepository : IBaseRepository<UserModel>{}

BaseRepository:

    public class BaseRepository<T>: IBaseRepository<T> where T :class, new(){
public IEnumerable<T> GetByPageUnite(SearchFilter filter, out long total){using (var conn = MySqlHelper.GetConnection()){return conn.GetByPageUnite<T>(filter.pageIndex, filter.pageSize, out total, filter.returnFields, filter.where, filter.param, filter.orderBy, filter.transaction, filter.commandTimeout);}}
}

UserRepository:

    public class UserRepository : BaseRepository<UserModel>, IUserRepository{}

最后的分页代码:

        /// <summary>/// 获取分页数据/// </summary>public static IEnumerable<T> GetByPageUnite<T>(this IDbConnection conn, int pageIndex, int pageSize, out long total, string returnFields = null, string where = null, object param = null,string orderBy = null, IDbTransaction transaction = null, int? commandTimeout = null){        int skip = 0;if (pageIndex > 0){skip = (pageIndex - 1) * pageSize;}StringBuilder sb = new StringBuilder();sb.AppendFormat("SELECT COUNT(1) FROM {0};",  where);sb.AppendFormat("SELECT {0} FROM {1} {2}  LIMIT {3},{4}", returnFields, where, orderBy, skip, pageSize);using (var reader = conn.QueryMultiple(sb.ToString(), param, transaction, commandTimeout)){total = reader.ReadFirst<long>();return reader.Read<T>();}}

Index视图:

@{Layout = "~/Views/Shared/_LayoutList.cshtml";
}<!DOCTYPE html>
<html><head><meta charset="UTF-8"><title>Table</title>
</head><body><div class="admin-main"><blockquote class="layui-elem-quote p10"><form id="formSearch" class="layui-form" action=""><div class="layui-form-item" style="margin-bottom:0px;"><label class="layui-form-label">用户名称:</label><div class="layui-input-inline"><input name="UserName" id="UserName" lay-verify="" autocomplete="off" class="layui-input"></div><label class="layui-form-label">角色名称:</label><div class="layui-input-inline">@Html.DropDownList("RoleId", null, "-请选择角色-", new Dictionary<string, object> { { "lay-verify", "required" } })</div><label class="layui-form-label">状态:</label><div class="layui-input-inline">@Html.StatusSelectHtml()</div>@Html.SearchBtnHtml()@Html.ResetBtnHtml()<div style="float:right;">@Html.TopToolBarHtml(ViewData["ActionFormRightTop"])</div></div></form></blockquote><div class="layui-field-box"><table id="defaultTable" lay-filter="defaultruv"></table><!-- 这里的 checked 的状态只是演示 -->@*<input type="checkbox" name="Status"  value="{{d.Id}}"  lay-skin="switch" lay-text="开启|禁用" lay-filter="statusSwitch" {{ d.Status == 1 ? 'checked' : '' }}>*@<script type="text/html" id="bar">@Html.ToolBarHtml(ViewData["ActionList"])</script></div></div><script>layui.config({base: '/plugins/app/'});layui.use(['table', 'common', 'form'], function () {var table = layui.table,form = layui.form,common = layui.common;//表格
            table.render({id: 'defaultReload', elem: '#defaultTable', height: 'full-112' //高度最大化减去差值
               , url: '/Permissions/User/List' //数据接口
               , page: true //开启分页
               , cols: [[ //表头
                 { checkbox: true, fixed: true },{ field: 'Id', title: 'Id', width: 80, fixed: 'left' }, { field: 'UserName', title: '用户名称', sort: true }, { field: 'RealName', title: '真实姓名' }, { field: 'RoleName', title: '角色名称' }, { field: 'Status', title: '状态', templet: '<div>{{showStatus(d.Status)}}</div>', unresize: true, width: 100, align: 'center' }, { field: 'CreateOn', title: '创建时间', width: 160, sort: true, templet: '<div>{{showDate(d.CreateOn)}}</div>' }, { field: '', title: '操作', toolbar: "#bar" }]]});var $ = layui.$, active = {reload: function () {var jsonWhere = urlToJson($("#formSearch").serialize());//执行重载
                    table.reload('defaultReload', {page: {curr: 1 //重新从第 1 页开始
                        }, where: jsonWhere});}};//服务器排序
            table.on('sort(defaultruv)', function (obj) {//尽管我们的 table 自带排序功能,但并没有请求服务端。//有些时候,你可能需要根据当前排序的字段,重新向服务端发送请求,如:
                table.reload('defaultReload', {initSort: obj //记录初始排序,如果不设的话,将无法标记表头的排序状态。 layui 2.1.1 新增参数
                  , where: { //请求参数
                      field: obj.field //排序字段
                    , order: obj.type //排序方式
                  }});});$('#btnSearch').on('click', function () {var type = $(this).data('type');active[type] ? active[type].call(this) : '';});//add
            $('#btnAdd').on('click', function () {common.openTop({title: '用户添加', w: '600px', h: '360px', content: '/Permissions/User/Add/'});});//监听工具条
            table.on('tool(defaultruv)', function (obj) {var data = obj.data;if (obj.event === 'detail') {common.openTop({detail: true,title: '角色详情', w: '600px', h: '360px', content: '/Permissions/User/Detail/' + data.Id, clickOK: function (index) {common.close(index);}});} else if (obj.event === 'del') {layer.confirm('确定要删除吗?', function (index) {$.ajax({url: "/Permissions/User/Delete",type: "POST",data: { "Id": data.Id },dataType: "json",success: function (data) {if (data.state == "success") {obj.del();//删除这一行
                                    common.msgSuccess("删除成功");} else {common.msgError("删除失败");}layer.close(index);//关闭弹框
                            }});});} else if (obj.event === 'edit') {common.openTop({title: '用户编辑', w: '600px', h: '360px', content: '/Permissions/User/Edit/' + data.Id});} else if (obj.event === 'reset') {layer.confirm('确定要初始化密码吗?', function (index) {$.ajax({url: "/Permissions/User/InitPwd",type: "POST",data: { "Id": data.Id },dataType: "json",success: function (data) {if (data.state == "success") {layer.close(index);//关闭弹框
                                    common.msgSuccess("密码初始化成功");} else {common.msgError("密码初始化失败");}layer.close(index);//关闭弹框
                            }});});}});});</script>
</body></html>

_LayoutBase模板页:

<!DOCTYPE html><html>
<head><meta name="viewport" content="width=device-width" /><title>@ViewBag.Title</title><link rel="stylesheet" href="~/plugins/layui/css/layui.css" media="all" /><link href="~/Content/global.css" rel="stylesheet" /><link href="~/Content/table.css" rel="stylesheet" /><script src="~/plugins/layui/layui.js"></script><script src="~/plugins/app/global.js"></script>
</head>
<body><div id="ajax-loader" style="cursor: progress; position: fixed; top: -50%; left: -50%; width: 200%; height: 200%; background: #fff; z-index: 10000; overflow: hidden;"><img src="~/Content/images/ajax-loader.gif" style="position: absolute; top: 0; left: 0; right: 0; bottom: 0; margin: auto;" /></div>@RenderBody()<script type="text/javascript">layui.config({base: '/plugins/app/',version: '1522709297490' //为了更新 js 缓存,可忽略
       });layui.use(['common'], function () {layer.config({skin: 'layui-layer-molv'})var $ = layui.jquery;$(function () {$('#ajax-loader').fadeOut();})})     </script>
</body>
</html>

代码结构基本上就这样了。

作为一名有追求的程序员,当看到代码连自己都受不了,我就开始抓狂,每次写代码的时候,脑袋里都是那几句话“不要重复你的代码、依赖于抽象....”

项目详细介绍和代码获取请移步:.net项目驱动学习

转载于:https://www.cnblogs.com/jiekzou/p/8962422.html

.net通用CMS快速开发框架——问题:Dapper通用的多表联合分页查询怎么破?相关推荐

  1. Admui 源码 是一个基于最新 Web 技术的企业级通用管理系统快速开发框架

    ** QQ194633530 索取源码 ** Admui 是一个基于最新 Web 技术的企业级通用管理系统快速开发框架,可以帮助企业极大的提高工作效率,节省开发成本,提升品牌形象. 您可以 Admui ...

  2. Admui 通用管理系统快速开发框架简介

    QQ194633530 简介 Admui是一个基于最新Web技术的企业级通用管理系统快速开发框架,可以帮助企业极大的提高工作效率,节省开发成本,提升品牌形象.您可以Admui为基础,快速开发各种MIS ...

  3. Thinkphp 6 + Vue 2 + ElementUI + Vxe-table 前后端分离的,一键生成代码和API接口的,通用后台管理系统 快速开发框架,开发小程序和APP的推荐框架!

    Thinkphp 6 + Vue 2 + ElementUI + Vxe-table 前后端分离的,一键生成代码和API接口的,通用后台管理系统 快速开发框架,开发小程序和APP的推荐框架! 概述 R ...

  4. 宝塔实测搭建开源PHP通用CMS建站系统源码

    大家好啊,我是测评君,欢迎来到web测评. 本期给大家带来一套开源PHP通用CMS建站系统的源码. 技术架构 主要语言框架 : PHP7.2 + mysql5.6 + Nginx + ThinkPHP ...

  5. php主控,IcePHP框架中的快速后台中的通用CRUD功能框架(五) SCrud 主控类

    /** * CRUD主控类 * @author bluehire */ class SCrud { const PATH_VIEW='crud'; //视图路径名 /** * 当前列表操作配置 * @ ...

  6. 织梦建站:织梦CMS整站源码通用安装教程(图文教程)

    织梦CMS整站源码通用安装教程: 今天先跟大家介绍一下dedecms织梦系统安装的方法步骤,以及织梦数据库还原的教程.详细请看图文讲解: 1. 运行 http://域名/install/index.p ...

  7. 通用mapper快速入门及原理简介

    一,mapper框架介绍 当我们在项目中使用Mybatis的开发者大多会因为繁多的XML映射配置而头痛不已,即使使用注解,大量的SQL语句也是不可避免的,当数据库表结构发生变动时,所有对应的sql和实 ...

  8. RION——一种快速、紧凑、通用的数据格式

    全文共5703字,预计学习时长17分钟 来源:Pexels 原始互联网对象符号(RION)是一种快速.紧凑.通用的数据格式.你可能会想:"又一个数据格式."它和CSV. XML.J ...

  9. dapper mysql通用类_Dapper.SqlMapper.Query的通用类型转换:DapperRow

    用过Dapper的人都知道,Dapper.SqlMapper.Query可以直接返回强类型对象,也就是我们所说的.NET中的类(CLASS).通常情况下我们都是这么用的,如下定义一个Model: pu ...

  10. Web经典BS快速开发框架,强大后台+简洁UI一体化开发工具

    本框架旨在为.NET开发人员提供一个Web后台快速开发框架,采用本框架,能够极大的提高项目开发效率. 整个框架包括三个版本:.net,.net core,java(开发中) 以上三个版本中,.NET为 ...

最新文章

  1. CSDN与易观联合发布《2017-2018中国人工智能产业路线图》
  2. js/jquery中实现图片轮播
  3. 201117阶段二SQLite数据库
  4. python字典的内置函数_python – 用于字典转换的特殊方法名称的内置函数
  5. 20141215胡思乱想
  6. eoeAndroid开发者大会
  7. 数据科学家为什要用Git?怎么用? 1
  8. ACS——网管的九阳神功
  9. ural 1024. Permutations
  10. GB2312 GBK BIG5
  11. android 英语单词音标获取
  12. wannier插值能带拟合1
  13. 数据结构—C语言:校园导航系统(最短路径两种算法:深度搜素以及Dijkstra)
  14. 宝哥面试题分享(07): Java中间件面试题
  15. c语言魔法书,C语言编程魔法书:基于C11标准
  16. linux 查看运行任务管理器,linux任务管理器快捷键有哪些
  17. 杭州师范大学钱江学院计算机专业分数线,分数线|杭州师范大学钱江学院2017-2018年分类专业分数线...
  18. 基于 Java 机器学习自学笔记 (第63-65天:集成学习之AdaBoost)
  19. 汉诺塔和小青蛙跳台阶问题
  20. 2021年G3锅炉水处理多少分及格及G3锅炉水处理操作证考试

热门文章

  1. Android 属性动画简单分析(二)
  2. 简单总结下8.25技术大会感受
  3. java机房收费管理系统课程设计_(c语言)机房收费管理系统课程设计
  4. cad无法修复图形文件_CAD应用技巧:DWG图形的“瘦身”
  5. golangd历史版本下载路径
  6. python-excel写入代码1
  7. python整型图_基于PIL的图像整形与裁剪矢量化
  8. 将数据加载到datagridview_JVM系列(一)-- Java类的加载机制
  9. php 请求 响应,发送http响应后继续处理php
  10. qt tcp不可以循环发送_Qt tcp 多线程下QTCPsocket不能发送数据~解决办法(2)