2011-01-09 6 views
2

私は現在フォーラムを開発中です。私はLINQとEFが初めてです。私のフォーラムでは、最新のトピックを最初に含むトピックのリストを表示するディスプレイがあります。LINQ to Entities orderbyとnullのコレクションに関する質問

問題は、「最新」はトピックの返信に関連していることです。だから私はトピックの投稿日付でリストを注文するのではなく、トピックの最後の返信の投稿日付でリストを注文したいと思います。新しい返答のあるトピックがリストの先頭にポップアップするようにします。すべてのトピックに少なくとも1つの返信があることが分かっていれば、これは簡単です。私はちょうどこれを行うでしょう:

var topicsQuery = from x in board.Topics 
        orderby x.Replies.Last().PostedDate descending 
        select x; 

しかし、多くの場合、トピックには返信がありません。その場合は、トピックの投稿日付を代わりに使用したいと考えています。トピックに応答がない場合、x.PostedDateで注文するようにlinqクエリ内に方法がありますか?私はこれで混乱していると助けていただければ幸いです。上記のクエリでは、返信があると仮定してx.Replies.Last()があるため、返信なしのトピックが壊れます。 LastOrDefault()は、返信があることを前提とするPostedDateプロパティにアクセスする必要があるため、機能しません。

ありがとうございました。

+0

すべての返事を受け取ってループし、if文を使用して回答があるかどうかを判断し、そのように新しいリストを作成することで、おそらくそれを行うことができます。しかし、クエリ内でそれを行い、毎回ループしない方法があれば、それは素晴らしいことです。 – Chev

答えて

7
var topicsQuery = from x in board.Topics 
        let lastActivityDate = x.Replies.Any() 
         ? x.Replies.Last().PostedDate 
         : x.PostedDate 
        orderby lastActivityDate descending 
        select x; 

編集:

あなたのコメントに答えるために、明示的にLINQの表現の構文は 'せ' ははありません。

var topicsQuery = board.Topics.Select(x => new { 
                Topic = x, 
                LastActivityDate = x.Replies.Any() 
                 ? x.Replies.Last().PostedDate 
                 : x.PostedDate 
            }) 
          .OrderByDescending(p => p.LastActivityDate) 
          .Select(r => r.Topic) 

EDIT2:これをさらに簡略化することができ

ニコラスが示唆されたとして、我々は中間select文などを削除することができ、次のようにしかし、あなたは(中間の選択式を使用して)同じことを達成することができますよくこれは異なる実行のためでない場合は可能ではないことに注意してください。

var topicsQuery = board.Topics 
     .OrderByDescending(x => x.Replies.Any() 
             ? x.Replies.Last().PostedDate 
             : x.PostedDate); 
+0

私はあなたを愛しています。あなたは私に時間の束を救った。私は気づいていませんでした。()と 'ありがとうございました+1し、時間が上がったときに受け入れて私にさせてくれます。 – Chev

+0

うれしいことを嬉しく思っています:) –

+0

チェーンのlinqでletキーワードをどのように使用するかの例を提供できますか? '.OrderBy(x => x.PostedDate) 'のように。 – Chev

0

トピックデータに新しいフィールドを追加することについて考えましたか? LastActivityDateのようなもの。トピックをPostedDateに設定し、返信が追加されるたびに更新します。

私はSQL Serverのエキスパートではありませんが、クエリで求めていることを実行しようとすると、インデックスが無視され、完全なテーブルスキャンが実行されるクエリが発生する可能性があります。

+0

これは実際に私がインラインSQLクエリで行った古いサイトでそれを行うのに使用した方法です。私はちょうどそれが冗長であったように感じ、上記の答えのおかげで私はそれを置き換えることができます。 – Chev

+0

これは、返信が行われたときに、この新しい返信フィールドを返信時間で更新し、トピックがリストの先頭に来ることを意味します。しかし、ユーザーがその返信を削除するとどうなりますか?以前の返信時刻に戻す簡単な方法はありません。私は今やっているように最後の返事を読まなければならないでしょう。最後の投稿IMHOに基づいて返信時間を動的にすることはずっと良いことです。 – Chev

2

私はコメントできません。 FWIW、これをコメントとして扱う。

var topicsQuery = from x in board.Topics 
       let lastActivityDate = x.Replies.Any() 
        ? x.Replies.Last().PostedDate 
        : x.PostedDate 
       orderby lastActivityDate descending 
       select x; 

あなたは典型的なフォーラムは特に、この特定のケースでは、多くの読み取りと書き込みの数いる

x.Replies.Last().PostedDate 

この

x.Replies.OrderByDesc(r => r.PostedDate).First().PostedDate 
+0

はい、非常に良いです。ナイスキャッチ。 – Chev

+0

あなたは今コメントすることができるはずです;) – NotMe

+0

@Chris、Yee-hooo、ここに行きます。 – Joker

0

変更する場合があります。したがって、余分なフィールドにLastPostDateをキャッシュすることを選択します。それはいくつかの冗長性と価値を最新に保つためにもう少しプログラミングを与えますが、私はほとんどの場合、それが最善の方法だと思います。

+0

真ですが、それぞれの返信で追加の書き込みです。また、LINQと遅延読み込みでは、最後の返信日を取得する方が効率的です。同じ数の読み取り、1つの書き込みが少なくなります。 – Chev