2011-12-22 3 views
0

나는 아주 SQL에 linq에 약간의 도움이 조금 필요합니다.Linq하려면 SQL 반환 - 테이블 결과 및 계산

기본적으로 저는 C#에서 메시지 게시판을 만들고 있습니다. 나는 3 개의 데이터베이스 테이블을 가지고있다 - 기본 정보는 다음과 같다.

게시판 forumid 이름

THREADS 는 forumid 제목 사용자 ID를 postid 이 텍스트 사용자 ID 날짜

은 기본적으로 내가 필요한 모든 것을 다시 가지고 싶어에게 threadid

게시물을 threadid 하나의 검색어로 THREADS (특정 FORUM에 대한) 페이지를 나열하고 해당 THREAD 행에 POSTS 수를 표시하고 마지막 POST가 해당 THREAD에 대한 것이 었으면합니다.

순간마다 나는 모든 스레드를 다시 가져 오는 중 각 결과 집합을 반복하고 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 내가 지금 각 스레드에서 게시물의 수와 각 스레드의 마지막 게시물의 날짜를 얻을 필요가있다.

은 어떤 도움이 가장 극명하게 될 것이다 :

편집

안녕 얘들 아. 지금까지 도와 주셔서 감사합니다. 기본적으로 나는 거의 다 왔어. 그러나 마지막 POST를 작성한 사람의 사용자 이름을 검색해야한다는 사실에 대해 초기 질문에서 중요한 부분을 남겼습니다. 따라서 USERS 테이블에서 p.userid와 u.userid를 결합해야합니다. 지금까지 나는이 다음 있었으나 결국 사용자 테이블과 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; 
    } 

내가 마지막으로 모두에게 감사와 그것의 그 부분을 알아 냈어 너희들 :). 내 유일한 문제는 이제 검색 결과 방법입니다. 순간 그것은 다음과 같이이다 : 나는 새로운 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(); 
    } 

참고 :

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

그래서 새로운 LINQ 방법으로이 절을 포함는. 어떤 도움을 기꺼이 수신 :

해결책 : 나는 해결책을 알아 냈하지만

나는 경우는 가장 좋은 하나 가장 효율적인 모른다. 어쩌면 너희들이 나에게 말할 수있다. 왜냐하면 나는 여전히 내 머리를 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

안녕하세요 제임스. 당신의 대답은 내가 찾는 것에 가장 가깝다고 생각합니다. 스레드의 최신 게시물의 사용자 이름을 가져와야하므로 질문을 편집했습니다. 어떤 도움/포인터가 가장 감사하게 받아 들여질 것입니다. – 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

같은이어야한다 - 제임스 나는 당신의 대답은 가장 가까운이고 내가되고 싶어 곳으로 근처에 나를 찾은 것 같아 by 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
  • 의 결과로 쿼리 많은 수의/삭제) 엔티티 많은 수의
  • 우리는 우리의 작업을 수행하는 실행 (다른) 쿼리 많은 수의

첫 번째 이유는 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가 Sql을 데이터베이스로 이동시켜 결과를 한 번에 한 행씩 가져 오는 게으른 방식으로 컬렉션에 액세스합니다. 이것은 엄청나게 비효율적이며, 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 프로젝트를 사용하여 달성 될 수있다. 캐시를 항목으로 저장하는 것이 얼마나 좋을까요. 음, 뭘 어쨌든! 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^_^

관련 문제