Fork me on GitHub
CQRS:CQRS+AJAX架构 之 查询(Q)模型设计

CQRS:CQRS+AJAX架构 之 查询(Q)模型设计

背景

准备采用CQRS架构,之前也简单的应用过(只是把读和写在程序级别进行了分离),这篇文章是我最近几天的思考,写下来希望大家多提意见。这篇文章不会涉及Command端的设计,重点关注如何设计查询。

真心的希望大家看完后能给出你们的意见和想法。

什么是CQRS

CQRS:Command Query Responsibility Separation。我喜欢职责分离,这也是我采用这种架构的原因,确实能带来单一职责的优点。

简单的CQRS

复杂的CQRS

CQRS的常见查询需求

下面是系统的一些查询需求:

查询面板

高级查询

数据行级别的权限

如:个人、部门、分公司、品种。

固定约束

如:启用、合法、租户ID。

需求总结

CQRS的查询设计

充分利用SQL和动态类型的优势,不做太多无谓的封装。

关键决策:

    1. 直接查询数据库返回Dynamic类型,不需要定义强类型。
    2. 直接用SQL,支持动态查询面板和动态数据行权限。目前没有找到封装SQL的理由,最多是在外围再封装一层,但是不会隐藏SQL(我之前写过一个简单的查询对象)。
    3. 利用一些策略防止SQL注入和权限提升(这篇文章不介绍)。

示例代码

下载地址:http://happy.codeplex.com/SourceControl/latest

AJAX程序

复制代码
 1 /// <reference path="Ext/ext-all-debug-w-comments.js" />
 2 
 3 Ext.onReady(function () {
 4     var query = {
 5         TableOrViewName: 'Users',
 6         WhereClause: "Name NOT LIKE '%段%'"
 7     };
 8 
 9     Ext.Ajax.request({
10         url: 'TestDynamicQuery/Fetch',
11         method: 'POST',
12         params: { query: Ext.encode(query) },
13         success: function (response) {
14             console.log(response.responseText);
15         }
16     });
17 
18     query = {
19         TableOrViewName: 'Users',
20         WhereClause: "Age >= 20 AND Age <= 27"
21     };
22 
23     Ext.Ajax.request({
24         url: 'TestDynamicQuery/Fetch',
25         method: 'POST',
26         params: { query: Ext.encode(query) },
27         success: function (response) {
28             console.log(response.responseText);
29         }
30     });
31 });
复制代码

万能查询控制器

复制代码
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 using System.Web.Mvc;
 7 
 8 using Newtonsoft.Json;
 9 
10 using Happy.Query;
11 
12 namespace Happy.Web.Mvc
13 {
14     /// <summary>
15     /// 动态查询控制器。
16     /// </summary>
17     public abstract class DynamicQueryController<TDynamicQueryService> : AjaxController
18         where TDynamicQueryService : IDynamicQueryService
19     {
20         /// <summary>
21         /// 动态查询服务。
22         /// </summary>
23         protected abstract TDynamicQueryService QueryService { get; }
24 
25         /// <summary>
26         /// 获取分页数据,面向表格。
27         /// </summary>
28         public ActionResult Page(DynamicQueryObject query)
29         {
30             var result = this.QueryService.Page(query);
31 
32             return this.Json(result);
33         }
34 
35         /// <summary>
36         /// 获取列表数据,面向不需要分页的表格或下拉框。
37         /// </summary>
38         public ActionResult Fetch(DynamicQueryObject query)
39         {
40             var result = this.QueryService.Fetch(query);
41 
42             return this.NewtonsoftJson(result);
43         }
44 
45         /// <summary>
46         /// 获取一个数据,面向表单。
47         /// </summary>
48         public ActionResult SingleOrDefault(DynamicQueryObject query)
49         {
50             var result = this.QueryService.Fetch(query);
51 
52             return this.NewtonsoftJson(result);
53         }
54     }
55 }
复制代码

万能查询对象

复制代码
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 
 7 namespace Happy.Query
 8 {
 9     /// <summary>
10     /// 动态查询对象。
11     /// </summary>
12     public sealed class DynamicQueryObject
13     {
14         /// <inheritdoc />
15         public DynamicQueryObject()
16         {
17             this.Columns = new List<string>();
18             this.Page = 1;
19             this.ItemsPerPage = 25;
20         }
21 
22         /// <summary>
23         /// 表或试图名字。
24         /// </summary>
25         public string TableOrViewName { get; set; }
26 
27         /// <summary>
28         /// 表或试图名字。
29         /// </summary>
30         public List<string> Columns { get; set; }
31 
32         /// <summary>
33         /// Where子句。
34         /// </summary>
35         public string WhereClause { get; set; }
36 
37         /// <summary>
38         /// Order子句。
39         /// </summary>
40         public string OrderClause { get; set; }
41 
42         /// <summary>
43         /// 第几页数据。
44         /// </summary>
45         public long Page { get; set; }
46 
47         /// <summary>
48         /// 每页条数。
49         /// </summary>
50         public long ItemsPerPage { get; set; }
51     }
52 }
复制代码

备注

写这篇文章的目的,是系统大家多给些意见,我想知道你们是如何应对这种查询需求的。

 

★快速评价★不错,支持一下! 
★快速评价★垃圾,还需努力!
 
posted on 2013-05-23 14:50  HackerVirus  阅读(217)  评论(0编辑  收藏  举报