2

RavenDBに保存されているオブジェクトの単純なセットがあります。

public class Question
{
    public string Id { get; set; }
    public DateTime CreatedOn { get; set; }
    public ICollection<User> Supporters { get; set; }
    public ICollection<Answer> Answers { get; set; }
}

public class Answer 
{
    public string Id { get; set; }
    public bool IsOfficial { get; set; }
}

次に、RavenDBにクエリを実行して、最初にサポーターの数、次に条件(質問に公式の回答がある場合)、および、質問の作成日で並べられた一連の質問を提供します。だから私はクエリを書きました:

var questions = DocumentSession.Query<Question>().AsQueryable(); 
questions = questions
                .OrderByDescending(x => x.Supporters.Count)
                .ThenByDescending(x => x.Answers.Any(a => a.IsOfficial)) //EDIT: source of exception
                .ThenByDescending(x => x.CreatedOn)
                .Take(15);                
var result = questions.ToList();

これは例外をスローします:

System.InvalidCastException: Unable to cast object of type 'System.Linq.Expressions.MethodCallExpressionN' to type 'System.Linq.Expressions.MemberExpression'

linq-to-objectsを使用し、最初の行に.ToList()を追加するだけで、クエリは論理的に正しく機能します。

var questions = DocumentSession.Query<Question>().Tolist().AsQueryable();
// next lines stay unchanged

パフォーマンスの問題があるため、これは実行したくありません(この変更により、フィルタリングの前にすべての質問がデータベースからメモリに読み込まれます)。

パフォーマンスに影響を与えずにこれを機能させる方法は?多分シェル私はインデックスを定義しますか?それではどのように見えるべきですか?

4

3 に答える 3

3

目的のカスタムインデックスは、基本的に、追加のフィールド(およびそれをサポートするためのロジック)を含むクラスの再現になります。現在のクラスにフィールドを追加する必要はないようですが、プロジェクトにクラスを追加しても大丈夫ですか?

次に例を示します。

public class Question_WithAnyOfficial: AbstractIndexCreationTask<Question>
{
    public class Question_WithAnyOfficial()
    {
        Map = questions => from question in questions
                           // New Anonymous Type
                           select new
                           {
                                Id = question.Id,
                                CreatedOn = question.CreatedOn,
                                Supporters = question.Supporters,
                                Answers = question.Answers,
                                AnyOfficial = question.Answers.Where(a => a.IsOfficial).Any()
                           };
    }
}

次に、これをクエリできます。

var questions = DocumentSession.Query<Question_WithAnyOfficial>()
                .OrderByDescending(x => x.Supporters.Count)
                .ThenByDescending(x => x.AnyOfficial)
                .ThenByDescending(x => x.CreatedOn)
                .Take(15)
                .ToList();         

アプリの起動時にインデックスを登録する必要があることを忘れないでください。

于 2012-04-17T19:52:47.480 に答える
2

RavenはLINQクエリ内でそのような計算をサポートできないため、これは機能するはずです(問題句が削除されました)。

var questions = DocumentSession.Query<Question>()
                .OrderByDescending(x => x.Supporters.Count)
                //.ThenByDescending(x => x.Answers.Any(a => a.IsOfficial))
                .ThenByDescending(x => x.CreatedOn)
                .Take(15);                
var result = questions.ToList();

AreAllAnswersOfficialそのロジックを含める場合は、クラスに(または同様の)というフィールドが必要です。次に、それを句の中に入れることができます:

var questions = DocumentSession.Query<Question>()
                .OrderByDescending(x => x.Supporters.Count)
                .ThenByDescending(x => x.AreAllAnswersOfficial)
                .ThenByDescending(x => x.CreatedOn)
                .Take(15);                
var result = questions.ToList();
于 2012-04-17T17:03:03.090 に答える
0

ベアアレクサンダーの応答に基づいて、私は次のようにこれを行いました:

public class QuestionByAnyOfficial : AbstractIndexCreationTask<Question, QuestionByAnyOfficial.Result>
{
    public class Result
    {
        public string Id;
        public bool AnyOfficial;
        public int SupportersCount;
        public DateTime CreatedOn;
    }

    public QuestionByAnyOfficial()
    {
        Map = questions => from question in questions                               
                           select new
                              {
                                  Id = question.Id,                                              
                                  AnyOfficial = question.Answers.Any(a => a.IsOfficial),
                                  SupportersCount = question.Supporters.Count,
                                  CreatedOn = question.CreatedOn
                              };            
    }
}

var questionIds = DocumentSession.Query<QuestionByAnyOfficial.Result, QuestionByAnyOfficial>()
                       .OrderByDescending(x => x.SupportersCount)
                       .ThenByDescending(x => x.AnyOfficial)
                       .ThenByDescending(x => x.CreatedOn)
                       .Take(NumberOfQuestions)
                       .Select(x => x.Id);
var questions = DocumentSession.Load<Question>(questionIds);
var result = questions.ToList();

それは機能し、私の元のバージョンよりも効率的だと思います。もっとエレガントな方法でそれができるなら、私はどんなアイデアでもありがたいです。よろしく。

于 2012-04-28T21:32:43.293 に答える