本文屬於OData系列
目錄
- 武裝你的WEBAPI-OData入門
- 武裝你的WEBAPI-OData便捷查詢
- 武裝你的WEBAPI-OData分頁查詢
- 武裝你的WEBAPI-OData資源更新Delta
- 武裝你的WEBAPI-OData之EDM
- 武裝你的WEBAPI-OData常見問題
- 武裝你的WEBAPI-OData使用Endpoint
- 武裝你的WEBAPI-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標準的檔案。