[英]Efficiently querying/ordering by Sum aggregate in related model in EfCore
我對 C#、.NET 和 EfCore 還很陌生,所以如果我在問題中遺漏了什么,請多多包涵並道歉。
假設我有以下關系
public class User
{
public Account Account {get; set;}
public string Foo {get; set;}
}
public class Account
{
public List<Transaction> Transactions {get; set;}
}
public class Transaction
{
public decimal Amount {get; set;}
public TransactionType TransactionType {get; set;}
}
public enum TransactionType
{
Credit = 1,
Debit = 2,
Refund = 3,
}
我想使用余額,每次檢索用戶模型時都需要計算余額。 對於這個例子,假設我需要按用戶的帳戶余額排序一個用戶列表,其中 Foo 是“Bar”
var query = db.Users
.Include(u => u.Account)
.ThenInclude(a => a.Transactions)
.Where(u => u.Foo == "Bar");
var orderedQuery = query
.OrderByDescending(u =>
(u.Account.Transactions
.Where(t => t.TransactionType == TransactionType.Credit || t.TransactionType == TransactionType.Refund)
.Sum(t => t.Amount))
- u.Account.Transactions
.Where(t => t.TransactionType == TransactionType.Debit)
.Sum(t => t.Amount)
)
);
// Build the List
return orderedQuery.Skip(...).Take(...).Select(x => new SomeDTO{/* Build some DTO's with User Info, Account Info and Balance */}).ToList();
上述工作,但效率低下。
我正在一個 asp.net 核心和 sql-server 項目中處理一個相當大的代碼庫和現有數據庫,所以我需要使用我所擁有的。 任何人都可以建議一種更好的方式來完成這種工作嗎?
你真的需要所有這些Include
嗎? 以后的排序聚合不需要它們。
var query = db.Users
.Include(u => u.Account)
.ThenInclude(a => a.Transactions)
.Where(u => u.Foo == "Bar");
您可以通過組合成一個分組來優化查詢的排序部分
var orderedQuery = query.OrderByDescending(u =>
u.Account.Transactions
.GroupBy(t => 1)
.Select(g =>
g.Where(t => t.TransactionType == TransactionType.Credit || t.TransactionType == TransactionType.Refund)
.Sum(t => t.Amount)
- g.Where(t => t.TransactionType == TransactionType.Debit)
.Sum(t => t.Amount)
)
);
Skip
Take
效率很低,因為它需要再次搜索整個列表。 謹慎的做法是將其全部緩存在客戶端中,然后再對其進行分頁。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.