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 }

備注

寫這篇文章的目的,是系統大家多給些意見,我想知道你們是如何應對這種查詢需求的。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM