RavenDBとLuceneQueryを使用したグループ化の動作に苦労しています。
IEnumerableはToArray()などを呼び出したときにのみ評価されるという印象を常に持っていました。
次のクエリは、わかりやすくするために2つの部分に分割されています。
TotalledBalanceListでToArray()が呼び出されるまで、クエリが評価されることは期待できません。グループ化は、すべてのデータにわたってサーバー上で行われることを期待しています。ただし、実際の結果は、.Take()で指定されたアイテムの数によって異なります。Take(1024)を使用しない場合、デフォルトの128アイテムの結果が返されます。
データセット全体でグループ化を実行できる必要があります。
using (var session = MvcApplication.RavenSession)
{
var computedBalanceList =
from c in session.Advanced.LuceneQuery<Journal, Ledger_ByDateAndDebitIdAndCreditIdAndValues>()
.Where(parameters)
.OrderBy(c => c.DateAsString).Take(1024)
select new LedgerBalanceDto
{
Account = account,
Name = queryName,
Debits = c.DebitId == account.Id
? c.DebitValue
: 0,
Credits = (c.CreditId == account.Id)
? c.CreditValue
: 0,
Currency = (c.DebitId == account.Id) ? c.DebitCurrency : c.CreditCurrency,
CurrencySymbol = (c.DebitId == account.Id) ? c.DebitCurrencySymbol : c.CreditCurrencySymbol,
};
var totalledBalanceList =
from balance in computedBalanceList
group new {balance.Debits, balance.Credits} by new {balance.Currency, balance.CurrencySymbol}
into grouping
select new LedgerBalanceDto
{
Account = account,
Currency = grouping.Key.Currency,
CurrencySymbol = grouping.Key.CurrencySymbol,
Debits = grouping.Sum(c => c.Debits),
Credits = grouping.Sum(c => c.Credits),
Name = queryName
};
return totalledBalanceList;
そしてインデックス:
public class Ledger_ByDateAndDebitIdAndCreditIdAndValues:AbstractIndexCreationTask<Journal>
{
public Ledger_ByDateAndDebitIdAndCreditIdAndValues()
{
Map = journals => from c in journals
select new {c.Date,c.DateAsString, c.DebitId, c.CreditId,c.DebitValue,c.CreditValue};
Index(x=>x.Date,FieldIndexing.Analyzed);
Index(x=>x.DateAsString,FieldIndexing.Analyzed);
Index(x=>x.DebitId,FieldIndexing.Analyzed);
Index(x=>x.CreditId,FieldIndexing.Analyzed);
Index(x=>x.DebitValue,FieldIndexing.Analyzed);
Index(x=>x.CreditValue,FieldIndexing.Analyzed);
Sort(x=>x.DateAsString,SortOptions.String);
}
}
また、グループ化がフィルターの「外側」で行われるようにクエリを書き直しましたが、まったく同じ結果が得られます。つまり、結果はTake()に依存します。
var totalledBalanceList = from balance in
from c in query
.Where(parameters)
.OrderBy(c => c.DateAsString)
select new LedgerBalanceDto
{
Account = account,
Name = queryName,
Debits = c.DebitId == account.Id
? c.DebitValue
: 0,
Credits = (c.CreditId == account.Id)
? c.CreditValue
: 0,
Currency = (c.DebitId == account.Id) ? c.DebitCurrency : c.CreditCurrency,
CurrencySymbol = (c.DebitId == account.Id) ? c.DebitCurrencySymbol : c.CreditCurrencySymbol,
}
group new {balance.Debits, balance.Credits} by new {balance.Currency, balance.CurrencySymbol}
into grouping
select new LedgerBalanceDto
{
Account = account,
Currency = grouping.Key.Currency,
CurrencySymbol = grouping.Key.CurrencySymbol,
Debits = grouping.Sum(c => c.Debits),
Credits = grouping.Sum(c => c.Credits),
Name = queryName
};
return totalledBalanceList;
これについての考えは大歓迎です。
Journalクラスの一部:
public class Journal
{
public string Id { get; set; }
public string DebitId{get;set;}
public string CreditId{get;set;}
public decimal? ExchangeRate { get; set; }
public decimal CreditValue {get;set;}
public decimal DebitValue {get;set;}
public string DebitCurrency {get;set;}
public string CreditCurrency {get;set;}
public decimal Nett
{
get { return _nett; }
set
{
_nett = value;
CreditValue = Math.Round(Nett, 2);
DebitValue = Math.Round(Nett * (ExchangeRate ?? 1), 2);
}
}
etc ...
}
サンプルデータIEnumerable <Journal
>:
Id DebitId CreditId Nett ExchangeRate DbCurr CrCurr DbVal CrVal
1 Expense1 Bank 100 2.03 BRL USD 203.00 100.00
2 Expense2 Bank 50 null USD USD 50.00 50.00
3 Bank Client1 300 null USD USD 300.00 300.00
4 Stock Bank 300 null USD USD 300.00 300.00
たとえば、銀行にクエリを実行するときに、DbValとCrValを合計して残高を計算できるようにしたいのですが、そのためには、(クエリに従って)どちらか一方をゼロにする必要があります。