一个用于论坛的LINQ查询

3

我是在编写这个论坛,由于我对LINQ不熟悉,因此当用户访问主页时遇到了问题。我想要一个显示论坛列表的表格,就像这样:

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

我有以下SQL表:

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)

Thank you...

3个回答

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

当然未经测试,请从这里开始,并检查它执行的SQL查询,让我知道是否需要优化。


1

如果您使用成员身份并且不想在您的 dbml 中包含 aspnet_Users,则可以显示用户的名称:

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

让您发布的示例更好的另一个更改是在帖子变量中添加orderbydescending: 然后,您可以从选择子句中删除4次重复的OrderByDescending:

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

甚至更加简洁:

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
}

在没有最后一篇文章的情况下测试此代码,如果Take(1)为空,可能会引发错误。


Take(1)如果为null不会抛出错误。但是似乎不可能将变量声明为LastPostThreadId = lastPost.ThreadId - 我必须使用.Select()?另外,是否可以返回强类型的值,而不是IOrderedQueryable<DateTime>等? - Morten
啊,是的,这是因为Take(1)也可以是Take(100),所以系统不知道你是否返回了单个ForumPost。这就是为什么你应该使用.FirstOrDefault()而不是.Take(1)。这将允许你使用lastPost.CreateDate,并将其作为DateTime返回,而不是IOrderedQueryable<DateTime>。 - Thomas Stock
无论如何,您都必须检查 null。最简单的方法是: LastPostTime =(lastPost!= null?lastPost.CreateDate:null) - Thomas Stock

0

这几乎可以解决问题(尽管它会生成一些可怕的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)
}

最后一件事 - 我有一个从SQL表'ForumPosts'到'Aspnet_Users'的关系,并且我想显示列Aspnet_Users.UserName作为LastPostUserName...怎么做呢?你如何优化整个查询?

将Aspnet_Users添加到您的dbml中,然后p.aspnet_user.Name就可以正常工作,对吗? - Thomas Stock
为了优化查询,您能复制粘贴生成的SQL吗? - Thomas Stock

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接