2009-05-31 8 views
3

Je suis le codage de ce forum et depuis que je suis nouveau à LINQ j'ai rencontré ce problème lorsque l'utilisateur accède à la page principale. Je veux un tableau affichant une liste des forums comme celui-ci:requête LINQ pour un forum

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

je les tables SQL suivantes:

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) 

Merci ...

Répondre

1

Pour afficher le nom de l'utilisateur si vous utilisez l'adhésion et que vous ne voulez pas inclure les aspnet_Users dans votre dbml:

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

Un autre changement pour rendre votre échantillon posté un peu mieux est d'ajouter le OrderByDescending dans les messages variables: Ensuite, vous pouvez déposer les 4 fois répétées OrderByDescending de la clause select:

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) 
} 

Ou encore plus propre:

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 
} 

test ce code quand il n'y a pas de derniers messages tho, je pense qu'il pourrait jeter une erreur si Take (1) est nul ..

+0

Take (1) ne renvoie pas d'erreur si elle est nulle. Mais il ne semble pas possible de déclarer des variables comme LastPostThreadId = lastPost.ThreadId - Je dois utiliser .Select()? Autre chose ... est-il possible de renvoyer des valeurs comme fortement typées au lieu de IOrderedQueryable et ainsi de suite? – Morten

+0

Ah oui, c'est parce que Take (1) pourrait aussi bien être Take (100), donc le système ne sait pas que vous retournez un seul ForumPost. C'est pourquoi vous devriez utiliser .FirstOrDefault() au lieu de .Take (1). Cela vous permettra d'utiliser lastPost.CreateDate et le retournera en tant que DateTime au lieu d'un IOrderedQueryable . –

+0

Vous devrez vérifier null de toute façon. Le plus simple est: 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)) 
} 

non testé ofcourse, mais essayez pour commencer à partir d'ici et vérifier les requêtes SQL qu'il exécute et faites-moi savoir s'il a besoin d'optimisation.

0

Cela fait presque le tour (bien qu'il génère une terrible SQL; -) ...)

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) 
} 

La dernière chose - j'ai une relation de table SQL 'ForumPosts' à 'Aspnet_Users' et je aime afficher la colonne Aspnet_Users.UserName comme LastPostUserName ... comment cela peut-il être fait? Et comment optimiseriez-vous toute la requête?

+0

ajouter les Aspnet_Users à votre dbml et p.aspnet_user.Name devrait fonctionner, non? –

+0

et pour optimiser la requête, pourriez-vous copier coller le sql généré? –