武裝你的WEBAPI-OData聚合查詢

本文屬於OData系列

目錄


ODATA v4提出了新的聚合查詢功能,這對於ODATA的基本查詢能力($expand等)是一個非常大的補充。ODATA支持的聚合查詢功能,可以對數據進行統計分析,例如求和、平均值、最大/最小值、分組等。

聚合查詢是通過$apply關鍵字實現的。使用$apply關鍵字可以指定一系列的聚合操作,以對數據進行處理。

GET /odata/Products?$apply=groupby((Category), aggregate(Price with sum as TotalSales))

該請求將返回按照產品類別(Category)分組的數據,並計算每個組的銷售總額(TotalSales)。

需要注意,聚合查詢出來的結果一般都不在EDM中註冊,因此無法對結果應用更多ODATA查詢,如果想解鎖這個能力,請手動在EDM中註冊這個類型。

聚合查詢示例

ODATA的強大之處在於可以賦予前端更多的自主權,讓他們自己獲得自己需要的數據,通過聚合查詢,我們可以實現非常多複雜的、以前只能在後端單獨實現的查詢。舉例說明,我們有以下三個實體類。

public class AttachDeviceType
    {
        /// <summary>
        /// 
        /// </summary>
        [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }
        /// <summary>
        /// 附加設備的類型
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// 描述
        /// </summary>
        public string Description { get; set; }
    }
   public abstract class AttachDeviceInfo
    {
        /// <summary>
        /// 
        /// </summary>
        [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }
        [Required]
        public string AttachDeviceId { get; set; }
        public string Name { get; set; }
        /// <summary>
        /// 附加設備的類型
        /// </summary>
        public virtual AttachDeviceType AttachDeviceType { get; set; }
        public string? Description { get; set; }

        public virtual DeviceInfo DeviceInfo { get; set; }
    }
   public class DeviceInfo
    {
        /// <summary>
        /// 
        /// </summary>
        [Key]
        [MaxLength(200)]
        public string DeviceId { get; set; }
        /// <summary>
        /// 地域位置的代碼
        /// </summary>
        public int? Adcode { get; set; }

        public virtual ICollection<AttachDeviceInfo> AttachDevices { get; set; }
    }

以上三個類定義了主設備、附加設備與從屬設備的類型,三者之間通過導航屬性進行連接。假定我們需要按照地域位置代碼進行分組查詢,查詢出每個地域的所有主設備的、附加設備的和不同的類型的數量。

/odata/DeviceInfos?$apply=groupby((Adcode), aggregate(AttachDevices/$count as NumAttachDevices, $count as NumDeviceInfos, AttachDevices/AttachDeviceType/$countdistinct as NumAttachDeviceTypes))

或者我們使用以attachdevice作爲目標

/odata/AttachDeviceInfo?$apply=groupby((DeviceInfo/Adcode), aggregate(
        $count as TotalDeviceInfo,
        attachdevices/$count as TotalAttachDevices,
        AttachDeviceType/$countdistinct as TotalAttachDeviceTypes))

思路沒有問題,但是實際執行會提示$count不是可用的aggregatebinder之類的錯誤(Binding OData QueryNode of kind 'Count' is not supported by 'AggregationBinder'.)。這是因爲$count已經是OData進行查詢得到的結果,這個結果不能在進行的聚合查詢了。

換一個思路,我們使用每一個實體對象的屬性作爲統計對象。

odata/attachdeviceinfos?$apply=groupby((deviceinfo/Adcode), aggregate($count as NumAttachDevices, deviceinfo/deviceid with countdistinct as NumDevices, attachdevicetype/id with countdistinct as NumTypes))

那麼就可以得到正確的結果:

[

    {

        "deviceInfo": {

            "adcode": 110105

        },

        "NumTypes": 1,

        "NumDevices": 1,

        "NumAttachDevices": 2

    },

    {

        "deviceInfo": {

            "adcode": 110108

        },

        "NumTypes": 1,

        "NumDevices": 1,

        "NumAttachDevices": 1

    }
]

當然,我們還可以組合使用filter查詢:

/odata/attachdeviceinfos?$apply=filter(deviceinfo/Adcode eq 110105)/groupby((deviceinfo/Adcode), aggregate($count as NumAttachDevices, deviceinfo/deviceid with countdistinct as NumDevices, attachdevicetype/id with countdistinct as NumTypes))

注意:在AXIOS中,前端發送如/之類的特殊字符會自動進行轉移,導致查詢請求失敗,請前端搜索禁止AXIOS自動轉移的方法,以保證發送的請求同POSTMAN發送的請求一致。

總結

使用聚合查詢可以方便將原來需要後端單獨編程的分類、統計等操作簡化,給予了前端非常大的自由度,同時減少了後端的接口數量。需要注意的是,很多操作在聚合查詢中語法可能有一些變化,請一定參閱ODATA的OASIS標準的文檔

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章