Когда групповой запрос оценивается в RavenDB?

Я борюсь с группировкой, используя RavenDB и LuceneQuery.

У меня всегда было впечатление, что IEnumerable оценивается только при вызове ToArray() и т. д.

Следующий запрос был разделен на две части для ясности.

Я бы не ожидал, что запрос будет оцениваться до тех пор, пока ToArray() не будет вызван для totalledBalanceList, я ожидаю, что группировка будет выполнена на сервере для всех данных. Однако фактический результат зависит от количества элементов, указанных в .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;

Любые мысли по этому поводу будут высоко оценены.

Часть класса журнала:

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 и вычислять баланс, но для этого мне нужно обнулить либо одно, либо другое (согласно запросу).


person Jeremy Holt    schedule 15.08.2012    source источник


Ответы (1)


Вы смешиваете LINQ и запрос Lucene, и это означает, что они будут оцениваться на клиент.

Вам нужно переместить большую часть этого в индекс и запросить его, используя session.Query, а не session.Advanced.LuceneQuery.

person Ayende Rahien    schedule 15.08.2012
comment
Как мне создать условную часть запроса, т.е. Debits=c.DebitId==id?DebitValue:0. К сожалению, из-за того, как структурированы данные, мне приходится использовать параметр для определения - person Jeremy Holt; 15.08.2012
comment
Орен, как мне создать условную часть запроса, т.е. Debits=c.DebitId==id?DebitValue:0 К сожалению, из-за того, как структурированы данные, мне приходится использовать входящий параметр, чтобы определить значение для суммирования на. Я пробовал всевозможные вещи, чтобы заставить класс Journal делать выводы из своих собственных данных, где DebitValue должно быть значением или 0. Я редактирую исходный вопрос, чтобы показать немного больше о классе и данных. (комментарии можно редактировать только 5 минут??) - person Jeremy Holt; 15.08.2012
comment
Благодаря вашим комментариям я решил реструктурировать данные в формат, пригодный для запросов. Я нахожусь в процессе переписывания нашего основного приложения с нуля, отказавшись от linq2sql/ef и перейдя на ravendb. - person Jeremy Holt; 15.08.2012