2011-12-22 10 views
0

私は非常にlinqのSQLと少し援助が必要です。Linq to Sql - テーブルの結果とカウントを返す

基本的に私はC#でメッセージボードを構築しています。私は3つのデータベーステーブルを持っています - 基本的な情報は次のとおりです。

フォーラム forumid 名

THREADS は forumid タイトル ユーザーIDに postid が テキスト ユーザーID 日

は基本的に私は、私は必要なすべてを取り戻すしたいにスレッドID

投稿をスレッドID 1つのクエリで私は(特定のフォーラムの)スレッドのページを一覧表示し、そのスレッドの行にPOSTSの数を表示し、その最後のPOSTがそのスレッド用であった場合にも表示します。

現時点では、すべてのスレッドが戻ってきて、それぞれの結果セットをループして、スレッドのPOSTカウントとそのスレッドの最新のポストについてPOSTテーブルを別々に呼び出しますが、これは問題を引き起こしますメッセージボードが大きくなるにつれてデータベースにヒットするという点で

私のLINQのは、これまでSQLへ:

public IList<Thread> ListAll(int forumid) 
    { 
     var threads = 
      from t in db.Threads 
      where t.forumid == forumid 
      select t; 
     return threads.ToList(); 
    } 

basicalyは、私は今、各スレッドでの投稿数と、各スレッドの最後の投稿の日付を取得する必要があります。

すべてのヘルプは、最も高く評価されるだろう:)

EDIT

こんにちはみんなを。これまでのご協力ありがとうございます。基本的に私はほとんどそこにいる。しかし、私は最初の質問から、最後のPOSTを行った人のユーザー名を取得する必要があるという点で重要な部分を残しました。したがって、USERS表のp.useridとu.useridを結合する必要があります。これまでのところ、私は次のことを持っていますが、ちょうどUSERテーブルでPOSTテーブルを結合するために、これを修正する必要があります。

public IList<ThreadWithPostInfo> ListAll(int forumid) 
    { 
     var threads = (from t in db.Threads 
            where t.forumid == forumid 
            join p in db.Posts on t.threadid equals p.threadid into j 
         select new ThreadWithPostInfo() { thread = t, noReplies = j.Count(), lastUpdate = j.Max(post => post.date) }).ToList(); 
     return threads; 
    } 

はUPDATE:

public IList<ThreadWithPostInfo> ListAll(int forumid) 
    { 
     var threads = (from t in db.Threads 
         from u in db.Users 
         where t.forumid == forumid && t.hide == "No" && t.userid == u.userid 
            join p in db.Posts on t.threadid equals p.threadid into j 
         select new ThreadWithPostInfo() { thread = t, deactivated = u.deactivated, lastPostersName = j.OrderByDescending(post => post.date).FirstOrDefault().User.username, noReplies = j.Count(), lastUpdate = j.Max(post => post.date) }).ToList(); 
     return threads; 
    } 

私は最終的にすべてのおかげでそれの一部を考え出しましたあなたの人の:)。私の唯一の問題は、検索結果メソッドです。

 where (t.title.Contains(text) || p.text.Contains(text)) && t.hide == "No" 

ので、新しいLINQメソッドにこの句を組み込む:私は新しいLINQコードにWHERE句を取得する必要があり

public IList<Thread> SearchThreads(string text, int forumid) 
    { 
     var searchResults = (from t in db.Threads 
          from p in db.Posts 
          where (t.title.Contains(text) || p.text.Contains(text)) && t.hide == "No" 
          && p.threadid == t.threadid 
          && t.forumid == forumid 
          select t).Distinct(); 
     return searchResults.ToList(); 
    } 

注:現時点では、このようなものです。すべてのヘルプは感謝して受信された:)

SOLUTION:

を私は解決策を考え出したが、その1最高または最も効率的かどうかは知りません。多分あなたは私がまだlinqの周りに頭を上げているので私に言うことができます。感謝:)

public IList<ThreadWithPostInfo> SearchThreads(string text, int forumid) 
    { 
     var searchResults = (from t in db.Threads 
          from p in db.Posts 
          where (t.title.Contains(text) || p.text.Contains(text)) && t.hide == "No" 
          && p.threadid == t.threadid 
          && t.forumid == forumid 
          select t).Distinct(); 

     //return searchResults.ToList();   

     var threads = (from t in searchResults 
          join p in db.Posts on t.threadid equals p.threadid into j 
         select new ThreadWithPostInfo() { thread = t, lastPostersName = j.OrderByDescending(post => post.date).FirstOrDefault().User.username, noReplies = j.Count(), lastUpdate = j.Max(post => post.date) }).ToList(); 
     return threads; 
    } 
+0

LINQの初心者なので、http://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811bにアクセスすることを強くお勧めします。このようなことをする方法を見つけようとするときに非常に役立ちます。 – JamieSee

答えて

0

私は、あなたが本当に探していることはこれだと思う:、あなたのコメントおよび更新された質問パー

 var threadsWithPostStats = from t in db.Threads 
            where t.forumid == forumid 
            join p in db.Posts on t.threadid equals p.threadid into j 
            select new { Thread = t, PostCount = j.Count(), LatestPost = j.Max(post => post.date) }; 

私は、この修正再表示を追加している:

 var threadsWithPostsUsers = from t in db.Threads 
            where t.forumid == forumid 
            join p in db.Posts on t.threadid equals p.threadid into threadPosts 
            let latestPostDate = threadPosts.Max(post => post.date) 
            join post in db.Posts on new { ThreadID = t.threadid, PostDate = latestPostDate } equals new { ThreadID = post.threadid, PostDate = post.date} into latestThreadPosts 
            let latestThreadPost = latestThreadPosts.First() 
            join u in db.Users on latestThreadPost.userid equals u.userid 
            select new { Thread = t, LatestPost = latestThreadPost, User = u }; 
+0

こんにちはJames。あなたの答えは、私が探しているものに最も近いと思います。スレッド内の最新の投稿のユーザー名を取得する必要があるため、私は自分の質問を編集しました。私はちょうどそれを正しく得ることができないので、任意の支援/ポインタが最も高く評価されるだろう:) – user1112150

+0

@ user1112150私はあなたの追加の基準を反映するために私の答えを更新しました。乾杯! – JamieSee

1
public IList<Thread> ListAll(int forumid) 
    { 
     var threads = 
      from t in db.Threads 
      where t.forumid == forumid 
      select new 
        { 
         Thread = t, 
         Count = t.Post.Count, 
         Latest = t.Post.OrderByDescending(p=>p.Date).Select(p=>p.Date).FirstOrDefault() 
        } 
    } 

がグループに慣れるために損はないだろうと

0

のようなものであるべき - ジェームズ私はあなたの答えが最も近かったと私はなりたかった場所の近くに私を得たと思いますLINQと集計で(Max、Min、Count)を指定します。このような

何か:

var forums = (from t in db.Threads 
     group t by t.forumid into g 
     select new { forumid = g.Key, MaxDate = g.Max(d => d.ForumCreateDate) }).ToList(); 

もして、グループでのLINQクエリ内の項目をカウントする方法については、こちらの記事をチェックアウト:
LINQ to SQL using GROUP BY and COUNT(DISTINCT)

LINQが集約: LINQ Aggregate with Sub-Aggregates

1

月をセッションごとにデータベース呼び出しが多すぎます....

データベースを呼び出す。照会するか書き込むかはリモート呼び出しであり、可能な限りリモート呼び出しの数を減らしたいと考えています。この警告は、プロファイラーが、単一のセッションがデータベースへの呼び出しを過剰に行っていることに気づいたときに発生します。これは、通常、セッションが使用される方法で潜在的な最適化を示すものです。

このことができるいくつかの理由がある:

  • ループ
  • 更新データベースを呼び出す(または挿入選択N + 1
  • の結果としてクエリの多数/削除)エンティティの数が多い
  • 私達は私達のタスクを実行するために実行する(異なる)クエリの数が多い

第1の理由として、Select N + 1の提案を見ることができます。Select N + 1は、データベースが最適ではない方法でアクセスされるデータアクセスの反パターンです。このサンプルコードを見てみましょう:この例では

// SELECT * FROM Posts 
var postsQuery = from post in blogDataContext.Posts 
       select post; 

foreach (Post post in postsQuery) 
{ 
    //lazy loading of comments list causes:  
    // SELECT * FROM Comments where PostId = @p0 
    foreach (Comment comment in post.Comments) 
    {  
     //print comment... 
    } 
} 

を、我々はポストのリストを読み込む(最初の選択)、次にオブジェクトグラフをトラバースしていることがわかります。しかし、私たちは怠惰な方法でコレクションにアクセスし、Linq to Sqlがデータベースに行き、結果を一度に1行戻します。これは信じられないほど非効率的で、Linq to Sql Profilerはこのような事態に遭遇するたびに警告を生成します。

この例のソリューションは簡単です。 DataLoadOptionsクラスを使用して、積極的に読み込みを行うオブジェクトモデルのどの部分を指定するかを指定します。

var loadOptions = new DataLoadOptions(); 
loadOptions.LoadWith<Post>(p => p.Comments); 
blogDataContext.LoadOptions = loadOptions; 

// SELECT * FROM Posts JOIN Comments ... 
var postsQuery = (from post in blogDataContext.Posts 
       select post); 

foreach (Post post in postsQuery) 
{ 
    // no lazy loading of comments list causes  
    foreach (Comment comment in post.Comments) 
    {  
     //print comment... 
    } 
} 

は、次のエンティティが多数使用ステートメントのバッチ処理で説明されて更新され、LINQ to SQLのの上に拡張のセットですPLinqOプロジェクトを、使用することによって達成することができます。キャッシュを1つのグループとしてアイテムを保存するのはどれだけクールですか。まあ、何を推測する! PLINQOはクールです!アイテムをキャッシュに保存するときは、PLINQOに問い合わせ結果がグループに属していて、その名前を指定する必要があります。キャッシュの無効化は、グルーピングのクールさが本当に現れる場所です。グループに属しているときにキャッシュとそのキャッシュで取られたアクションのカップリングはありません。この例をチェックアウト:

public ActionResult MyTasks(int userId) 
{ 
    // will be separate cache for each user id, group all with name MyTasks 
    var tasks = db.Task 
     .ByAssignedId(userId) 
     .ByStatus(Status.InProgress) 
     .FromCache(CacheManager.GetProfile().WithGroup("MyTasks")); 

    return View(tasks); 
} 

public ActionResult UpdateTask(Task task) 
{ 
    db.Task.Attach(task, true); 
    db.SubmitChanges(); 

    // since we made an update to the tasks table, we expire the MyTasks cache 
    CacheManager.InvalidateGroup("MyTasks"); 
} 

PLinqOあなたはいくつかの異なるクエリを取り、単一のリモート呼び出しでデータベースに送信することができ先物、と呼ばれる機能を使用して、クエリのバッチ処理の概念をサポートしています。これにより、リモート呼び出しの回数が大幅に削減され、アプリケーションのパフォーマンスが大幅に向上します。

cmiiw^_^

関連する問題