asp.net 网页动态查询条件的实现

场景

最近有一个需求,会在 mongodb 中插入各种类型的数据,算是记录业务日志的数据库吧。
因为业务对象类型都不同,所以插入的数据格式也完全不同。
除此之外,还需要提供一个查询界面,可以搜索数据。
插入数据没任何问题,但是查询就…

查询设计方案

首先想到的是让用户直接输入 mongodb 查询语法,类似 json 格式。但是使用者虽然也是开发,可都不熟悉这个语法,所以放弃了。
第二个想法是让用户输入 SQL 语句,然后转换… 结果以失败而告终。
最后,看到了 iTunes 智能播放列表的交互设计:

这里,你可以插入一个条件,也可以插入一组条件(相当于插入了一个括号,括号内是许多条件)。

图中的表达式可以认为是: Score > 3 && Type == "Music" && Author == "" && ( Author == "" && Author == "" && Author == "")

也就是说,这样的交互完全可以实现各种嵌套逻辑。

数据结构
为了设计出这样的结构,肯定要先好好想一下数据结构。

分析后感觉,这里其实就两种类型,一个可以认为是 QueryGroup,一个可以认为是 QueryItem。

代码如下:


代码如下:

public class QueryGroup
{
public GroupType GroupType { get; set; }
public List<QueryItem> Items { get; set; }
public List<QueryGroup> Groups { get; set; }
}

public class QueryItem
{
public string Name { get; set; }
public QuerySymbol OperatorType { get; set; }
public string Value { get; set; }
public DataType ValueType { get; set; }
}

QueryGroup 包含了一组查询条件,也包含了一组子 QueryGroup,另外还有一个重要的属性 GroupType ,代表这组数据的逻辑关系是 And 还是 Or。也就是上述界面中的“任何”和“任意”选项。

QueryItem 内部属性分别是字段名、逻辑操作类型(等于、不等于、大于…)、和属性类型(整数、文本…)。

设计完数据结构后会有几个难点:

1.前端交互怎么设计?
2.如何传给后端?
3.后端得到数据后如何转换成查询表达式?
那下面就一个个来攻克吧!

前端设计交互

这里用的是 bootstrap ,界面非常好看!

先来看看前端设计方案吧,上面是动态条件,下面是一些固定的条件。

这里的结构和上面的数据结构一致,把 html 分两类,QueryGroup 和 QueryItem。

分别放在两个隐藏的 div 中,当做模版使用。

代码如下:


代码如下:

<div style="display: none;">
<div class="query-group-template">
<div class="query-group well">
<div class="query-title">
<span class="help-inline">匹配以下</span>
<select class="input-small group-type">
<option value="1">全部</option>
<option value="2">任何</option>
</select>
<span class="help-inline">规则:</span>
<button type="button" class="btn btn-mini btn-success add-query-item" title="增加一个条件">
<i class="icon-plus icon-white"></i>
</button>
<button type="button" class="btn btn-mini btn-info add-query-group" title="增加一组条件">
<i class="icon-th-list icon-white"></i>
</button>
<button type="button" class="btn btn-mini btn-danger delete-query-group" title="删除这组条件">
<i class="icon-minus icon-white"></i>
</button>
</div>
</div>
</div>
<div class="query-item-template">
<div class="query-item">
<input type="text" value="" placeholder="字段名" title="字段名" class="property-name" />
<select class="input-mini operate-type" title="条件">
<option value="1">==</option>
<option value="2">!=</option>
<option value="3">></option>
<option value="4">>=</option>
<option value="5"><</option>
<option value="6"><=</option>
<option value="7">LK</option>
</select>
<input type="text" class="query-value" value="" placeholder="值" title="值" />
<select class="input-medium value-type">
<option value="3">String</option>
<option value="1">Int</option>
<option value="2">Double</option>
<option value="4">DateTime</option>
</select>
<button type="button" class="btn btn-mini btn-danger delete-query-item" title="删除条件">
<i class="icon-minus icon-white"></i>
</button>
</div>
</div>
</div>

这里其实不难,最关键的地方其实是各个按钮的事件了。
仔细看一下,一共有4个按钮:
上面三个分别是:增加一行条件、增加一组条件、删除本组条件。
单个条件右边一个是:删除此条件。
这里逻辑其实非常简单:


代码如下:

$('#queryContainer').append($('.query-group-template>.query-group').clone())
$('#queryContainer>.query-group').first().find('.delete-query-group').remove();
$('button.add-query-item').live('click', function () {
$(this).parent().parent().append($('.query-item-template>.query-item').clone());
return false;
});
$('button.add-query-group').live('click', function () {
$(this).parent().parent().append($('.query-group-template>.query-group').clone());
return false;
});
$('button.delete-query-group').live('click', function () {
if (!$(this).parent().parent().parent().hasClass('query-group')) { return false; }
$(this).parent().parent().remove();
return false;
});
$('button.delete-query-item').live('click', function () {
$(this).parent().remove();
return false;
});

另外,看代码前两行,第一次加载的时候别忘了先加一组条件,并且把默认组的“删除本组条件”这个按钮去掉吧。
前端数据处理
界面交互真的很简单,但是怎么把这个数据传给后端呢?
把表单一个个字段取出来传过去?那后端要哭了… 完全是乱七八糟的一堆数据。
那… 既然查询条件的结构是非常清晰的,为什么不能先变成 javascript 中的对象呢?
然后,把这个对象序列化…
再然后,把 json 传给后端…
最后,后端定义同样结构的类型,然后反序列化…
也就是说,在这个交互的过程中,只需要把表单数据实例化成 javascript 中的对象即可!
那我先来定义两个对象(注意字段名一定要和后端一样):


代码如下:

function QueryGroup() {
this.GroupType = 0;
this.Items = [];
this.Groups = [];
}
function QueryItem() {
this.Name = '';
this.OperatorType = 0;
this.Value = '';
this.ValueType = 0;
}

实例化成对象的方法也非常简单,需要用到递归,基本逻辑是:
对最外层 QueryGroup 内部的对象循环一次,如果是 QueryItem 就指着取值,如果还是 QueryGroup 就递归调用此方法。
代码如下:


代码如下:

function GetQueryGroup(group) {
group = $(group);
var queryGroup = new QueryGroup();
queryGroup.GroupType = parseInt(group.find('.group-type').val());
var queryItems = group.children('.query-item');
for (var k = 0; k < queryItems.length; k++) {
var queryItem = new QueryItem();
queryItem.Name = $(queryItems[k]).find('.property-name').val();
queryItem.OperatorType = parseInt($(queryItems[k]).find('.operate-type').val());
queryItem.Value = $(queryItems[k]).find('.query-value').val();
queryItem.ValueType = parseInt($(queryItems[k]).find('.value-type').val());
queryGroup.Items.push(queryItem);
}
var childGroups = group.children('.query-group');
for (var k = 0; k < childGroups.length; k++) {
queryGroup.Groups.push(GetQueryGroup(childGroups[k]));
}
return queryGroup;
}

最后,表单是表单提交,最终会生成一个对象,把这个对象序列化成 json 然后编码一下:
encodeURIComponent(JSON.stringify(item))
后端数据处理
后端数据处理主要分两个部分:反序列化、转换成查询条件。
数据结构在上面已经定义过了,只要字段名和 json 中的一样,就可以直接反序列化。


代码如下:

var json = Uri.UnescapeDataString(Request["query"]);
var item = JsonConvert.DeserializeObject<QueryGroup>(json);

两行代码,它就变成 .net 中的对象了!
最后,生成查询条件其实也非常简单,也是一个方法,递归调用即可,基本逻辑和前段把表单数据实例化的过程很像。
我在 QueryGroup 中扩展了一个方法,其中 ICriteria 和 IMongoQuery 结构类似,用过 mongodb 的同学当它是 IMongoQuery 即可,它只是包了一层,最终也是生成 IMongoQuery。


代码如下:

public class QueryGroup
{
public GroupType GroupType { get; set; }
public List<QueryItem> Items { get; set; }
public List<QueryGroup> Groups { get; set; }
public ICriteria ToICriteria()
{
ICriteria result = null;
foreach (var criteria in GetICriteriaList())
{
if (result == null)
{
result = criteria;
continue;
}
if (GroupType == Model.GroupType.AndAlse)
{
result = result.Add(criteria);
continue;
}
if (GroupType == Model.GroupType.OrElse)
{
result = result.Or(criteria);
continue;
}
}
return result;
}
private List<ICriteria> GetICriteriaList()
{
var list = new List<ICriteria>();
foreach (var item in Items)
{
list.Add(new Criteria(item.Name, item.OperatorType, new QueryValue(item.ValueType, item.Value, FieldHierarchyLevel.Child)));
}
foreach (var group in Groups)
{
list.Add(group.ToICriteria());
}
return list;
}
}

得到查询条件对象后,直接调用相关查询方法即可。

后记
本场景中用的是 mongodb ,所以最终转换出来的是 mongodb 查询对象。其实,如果是转换 SQL 也是非常方便的。

另外,稍微复杂一点,转换成 .net 中的表达式树也是木有问题的!

最后附上 gif 的 Demo

作者:Dozer

(0)

相关推荐

  • asp.net中gridview的查询、分页、编辑更新、删除的实例代码

    1.A,运行效果图 1.B,源代码/App_Data/sql-basic.sql 复制代码 代码如下: use mastergoif exists(select * from sysdatabases where name='db1')begin    drop database db1endgocreate database db1gouse db1go-- ================================-- ylb:1,类别表-- =====================

  • asp.net IList查询数据后格式化数据再绑定控件

    一.先讲最基本的 DataSet绑定操作,GridView为例. 当操作查询得一个 DataSet ds 后,可以进行一些数据的格式化,如: 复制代码 代码如下: foreach (DataRow dr in ds.Tables[0].Rows) { if (dr["Depth"].ToString() != "1") { dr["ColumnName"] = StringHelper.StringOfChar(Convert.ToInt32(d

  • 用js实现QQ在线查询功能

    这段程序的方法是利用XMLHTTP来读取腾讯网站的相应HTML代码获取QQ的头像,根据这个想法,我们还可以抓取很多其他网站的信息,如天气预报.新闻等等. <script language="JavaScript">  <!--   function getFaceImg(QQcode)   {   var Re=new RegExp("^[1-9]{1}\d+$","g");   if (!QQcode !Re.test(QQc

  • asp.net连接数据库 增加,修改,删除,查询代码

    复制代码 代码如下: '数据库连接 Public Sub connectionDB() Try serverUrl = readFromIni(My.Application.Info.DirectoryPath & "\config.dll", "Service Information", "IPAddress") serverID = readFromIni(My.Application.Info.DirectoryPath &

  • 基于ASP实现QQ在线查询功能

    本文给大家分享的qq在线查询功能代码非常简单,具体内容如下: 这段程序的方法是利用XMLHTTP来读取腾讯网站的相应HTML代码获取QQ的头像,根据这个想法,我们还可以抓取很多其他网站的信息,如天气预报.新闻等等. <script language="JavaScript"> <!-- function getFaceImg(QQcode) { var Re=new RegExp("^[1-9]{1}/d+$","g"); if

  • ASP多条件查询功能实现代码(多关键词查询)

    经过多次研究写出了如下代码,有需要的可以参考下 复制代码 代码如下: kd=server.HTMLEncode(request("keyword"))if kd<>"" then    kd=trim(kd)'kd=replace(kd," ","")  kd=replace(kd,"'","")  kd=replace(kd,"%","&quo

  • asp查询xml的代码 不刷新页面查询的方法

    以下为引用的内容: <html> <head> <title>不刷新页面查询的方法</title> <meta http-equiv="Content-Type" content="text/html; charset=gb2312"> </head> <script language="javascript"> <!--初始化,将数据岛中数据装入列表框中-

  • asp.net 网页动态查询条件的实现

    场景 最近有一个需求,会在 mongodb 中插入各种类型的数据,算是记录业务日志的数据库吧. 因为业务对象类型都不同,所以插入的数据格式也完全不同. 除此之外,还需要提供一个查询界面,可以搜索数据. 插入数据没任何问题,但是查询就- 查询设计方案 首先想到的是让用户直接输入 mongodb 查询语法,类似 json 格式.但是使用者虽然也是开发,可都不熟悉这个语法,所以放弃了. 第二个想法是让用户输入 SQL 语句,然后转换- 结果以失败而告终. 最后,看到了 iTunes 智能播放列表的交互

  • Java中JDBC实现动态查询的实例详解

    一 概述 1.什么是动态查询? 从多个查询条件中随机选择若干个组合成一个DQL语句进行查询,这一过程叫做动态查询. 2.动态查询的难点 可供选择的查询条件多,组合情况多,难以一一列举. 3.最终查询语句的构成 一旦用户向查询条件中输入数据,该查询条件就成为最终条件的一部分. 二 基本原理 1.SQL基本框架 无论查询条件如何,查询字段与数据库是固定不变的,这些固定不变的内容构成SQL语句的基本框架,如 select column... from table. 2.StringBuilder形成D

  • asp.net为网页动态添加description描述信息的方法

    本文实例讲述了asp.net为网页动态添加description描述信息的方法.分享给大家供大家参考.具体分析如下: 这段代码可以修改网页的head区的description meta HtmlMeta desc = new HtmlMeta(); desc.Name = "Description"; desc.Content = "描述"; Page.Header.Controls.Add(desc); 希望本文所述对大家的asp.net程序设计有所帮助.

  • asp.net为网页动态添加关键词的方法

    本文实例讲述了asp.net为网页动态添加关键词的方法.分享给大家供大家参考.具体如下: 这段代码可以修改网页的keyword meta HtmlMeta keywords = new HtmlMeta(); keywords.Name = "keywords"; keywords.Content = "关键词"; Page.Header.Controls.Add(keywords); 希望本文所述对大家的asp.net程序设计有所帮助.

  • Mybatis 实现动态组装查询条件,仿SQL模式

    目的: 以前比较习惯使用Hibernate,后来觉得mybatis不能按我想要的自动组装为SQL查询条件,所以提供该工具类: 效果图: 如图所示,根据条件自动组装查询条件,下面来说一下实现方法: 1. ServiceImpl书写注意项 Page<SysLogin> resultPage = null; try { PageHelper.startPage(pager.getCurrentPage(), pager.getPageSize()); // 判断是否有分页 if (ObjectHel

  • mybatis的mapper特殊字符转移及动态SQL条件查询小结

    目录 前言 条件查询 快速入门 if标签 where标签 choose when otherwise标签 foreach标签 场景案例 前言 我们知道在项目开发中之前使用数据库查询,都是基于jdbc,进行连接查询,然后是高级一点jdbcTemplate进行查询,但是我们发现还是不是很方便,有大量重复sql语句,与代码偶合,效率低下,于是就衍生出来ORM框架,如Mybatis,Hibernate,还有SpringBoot的,Spring Data JPA 条件查询 我们知道在mybatis map

  • 使用JPA+querydsl如何实现多条件动态查询

    目录 JPAquerydsl多条件动态查询 介绍一下querydsl 看源码 springdataJPA和querydsl 什么是SpringDataJPA?什么是QueryDSL? @Mapper实体-模型映射 项目整体流程 疑问 JpaRepository SimpleJpaRepository 写一个Repository继承JpaRepository之后 spring-data-jpa的相关语法 JPA querydsl多条件动态查询 相信很多人在做订单管理的时候会用到多条件的检索,比如说

  • XML卷之实战锦囊(2):动态查询

    动机: 查询功能是我们在网站上见过的最普遍也是最常用的一个功能模块了.以往的信息查询都是连接到数据库的,每一次点击都必须要后台数据库的支持.然而很多情况下用户往往只针对某一部分的数据进行操作,这样不但服务器的负担加重,而且严重的影响用户浏览的速度. 针对这种情况我们需要将用户需要的某一部分数据以XML的方式传递到客户端,用户对这些数据可以很方便的进行操作.既方便了用户,又减轻了服务器数据库的负担.何乐而不为呢!而且这项功能可以通用到其他众多模块,因此添加了这个动态查询功能. 材料: XML卷之动

  • Spring Data JPA实现动态查询的两种方法

    前言 一般在写业务接口的过程中,很有可能需要实现可以动态组合各种查询条件的接口.如果我们根据一种查询条件组合一个方法的做法来写,那么将会有大量方法存在,繁琐,维护起来相当困难.想要实现动态查询,其实就是要实现拼接SQL语句.无论实现如何复杂,基本都是包括select的字段,from或者join的表,where或者having的条件.在Spring Data JPA有两种方法可以实现查询条件的动态查询,两种方法都用到了Criteria API. Criteria API 这套API可用于构建对数据

  • Spring Data JPA中的动态查询实例

    spring Data JPA大大的简化了我们持久层的开发,但是实际应用中,我们还是需要动态查询的. 比如,前端有多个条件,这些条件很多都是可选的,那么后端的SQL,就应该是可以定制的,在使用hibernate的时候,可以通过判断条件来拼接SQL(HQL),当然,Spring Data JPA在简化我们开发的同时,也是提供了支持的. 通过实现Criteria二实现的动态查询,需要我们的Repo接口继承JpaSpecificationExecutor接口,这是个泛型接口. 然后查询的时候,传入动态

随机推荐