2009-05-31 12 views
3

Ich bin dieses Forum codieren und da ich neu bei LINQ bin lief ich in dieses Problem, wenn der Benutzer die Hauptseite erreicht. Ich möchte eine Tabelle, die eine Liste von Foren wie diese Anzeige:LINQ-Abfrage für ein Forum

Forum --- Topics (count) --- Posts (count) --- LastPostUserId --- LastPostTime 

Ich habe folgende SQL-Tabellen:

Forums: 
ForumId (int32), 
Title (string), 
Description (string) 

ForumThreads: 
ThreadId (int32), 
ForumId (int32), 
UserId (guid), 
Subject (string), 
Views (int32), 
CreateDate (DateTime) 

ForumPosts: 
PostId (int32), 
ThreadId (int32), 
UserId (guid), 
Post (string), 
CreateDate (datetime) 

Danke ...

Antwort

1

Für den Namen des Benutzers angezeigt wird, wenn Sie die Mitgliedschaft verwenden und Sie wollen nicht die aspnet_Users in Ihrem dbml enthalten:

... 
LastPostUserId = posts.OrderByDescending(p=>p.PostId).Take(1).Select(p=> Membership.GetUser(p.UserId)) 
... 

Eine weitere Änderung Ihrer posted Probe ein bisschen besser zu machen, ist die OrderByDescending hinzuzufügen in die Beiträge Variable: Dann können Sie die 4-mal fallen OrderByDescending aus der select-Klausel wiederholt:

from forum in Forums 
let posts = ForumPosts.Where(p => p.ForumThreads.ForumId.Equals(forum.ForumId)).OrderByDescending(p=>p.PostId) 
select new 
{ 
    Forum = forum.Title, 
    Description = forum.Description, 
    Topics = forum.ForumThreads.Count(), 
    Posts = posts.Count(), 
    LastPostId = posts.Take(1).Select(p=>p.PostId), 
    LastPostThreadId = posts.Take(1).Select(p=>p.ThreadId), 
    LastPostUserId = posts.Take(1).Select(p=>p.UserId), 
    LastPostTime = posts.Take(1).Select(p=>p.CreateDate) 
} 

Oder noch sauberer:

from forum in Forums 
let posts = ForumPosts.Where(p => p.ForumThreads.ForumId.Equals(forum.ForumId)) 
let lastPost = posts.OrderByDescending(p=>p.PostId).Take(1) 
select new 
{ 
    Forum = forum.Title, 
    Description = forum.Description, 
    Topics = forum.ForumThreads.Count(), 
    Posts = posts.Count(), 
    LastPostId = lastPost.PostId, 
    LastPostThreadId = lastPost.ThreadId, 
    LastPostUserId = lastPost.UserId, 
    LastPostUserName = Membership.GetUser(lastPost.UserId), 
    LastPostTime = lastPost.CreateDate 
} 

Testen Sie diesen Code, wenn es keine letzten Beiträge tho, ich denke, es könnte einen Fehler aus, wenn Nehmen (1) null ist ..

+0

Take (1) wirft keinen Fehler, wenn es null ist. Aber es scheint nicht möglich, Variablen als LastPostThreadId = lastPost.ThreadId zu deklarieren - ich muss .Select() verwenden? Eine andere Sache .. ist es möglich, Werte als stark typisiert statt IOrderedQueryable und so weiter? – Morten

+0

Ah ja, das liegt daran, dass Take (1) auch Take (100) sein könnte, damit das System nicht weiß, dass Sie eine einzelne ForumPost zurückgeben. Deshalb sollten Sie .FirstOrDefault() anstelle von .Take (1) verwenden. Dadurch können Sie lastPost.CreateDate verwenden und es als DateTime anstelle von IOrderedQueryable zurückgeben. –

+0

Sie müssen sowieso auf Null überprüfen. Der einfachste Weg ist: LastPostTime = (lastPost! = Null? LastPost.CreateDate: null) –

2
from forum in forums 
from posts in db.ForumPosts.Where(p => p.Thread.ForumId.Equals(forum.ForumId)) 
select new 
{ 
Forum = forum.Title, 
Topics = forum.ForumThreads.Count(), 
Posts = posts.Count(), 
LastPostBy = posts.OrderByDescending(p => p.CreateDate).FirstOrDefault(p => p.UserId), 
LastPostTime= posts.Max(p => p.CreateDate)) 
} 

ungetestet ofcourse, aber versuchen Um von hier aus zu starten und die SQL-Abfrage (n) zu überprüfen, die es ausführt, lassen Sie mich wissen, ob es optimiert werden muss.

0

Diese fast funktioniert der Trick (obwohl es eine schreckliche SQL erzeugt; -) ...)

from forum in Forums 
let posts = ForumPosts.Where(p => p.ForumThreads.ForumId.Equals(forum.ForumId)) 
select new 
{ 
    Forum = forum.Title, 
    Description = forum.Description, 
    Topics = forum.ForumThreads.Count(), 
    Posts = posts.Count(), 
    LastPostId = posts.OrderByDescending(p=>p.PostId).Take(1).Select(p=>p.PostId), 
    LastPostThreadId = posts.OrderByDescending(p=>p.PostId).Take(1).Select(p=>p.ThreadId), 
    LastPostUserId = posts.OrderByDescending(p=>p.PostId).Take(1).Select(p=>p.UserId), 
    LastPostTime = posts.OrderByDescending(p=>p.PostId).Take(1).Select(p=>p.CreateDate) 
} 

Letzte Sache - ich eine Beziehung von SQL-Tabelle ‚Forumbeiträge‘ auf ‚Aspnet_Users‘ haben, und ich würde möchte die Spalte Aspnet_Users.UserName als LastPostUserName anzeigen ... wie kann das gemacht werden? Und wie würden Sie die gesamte Abfrage optimieren?

+0

die Aspnet_Users zu Ihrem dbml und p.aspnet_user.Name hinzufügen sollten einfach funktionieren, Nein? –

+0

und zum Optimieren der Abfrage, könnten Sie die generierten sql kopieren? –