【问题标题】:Using LINQ in C# for paginated results在 C# 中使用 LINQ 获取分页结果
【发布时间】:2012-11-11 19:19:13
【问题描述】:

我正在寻找一种模式的设计解决方案,我将不得不在我正在设计的网站中重复很多次。它将是 ASP.NET MVC 前端,使用 NHibernate 连接到 SQL 数据库的 C# WCF Web 服务。

这是一个社交网站,因此可以在这里想象一下 facebook 以获得概念性的想法。我正在寻找的是一种高效且高效的方式来返回大型数据集的分页结果,例如,用户可能有 150 封电子邮件。我想根据他们所在的页面一次返回 10 个,显然只返回与页面相关的 10 个,而不是必须将所有 150 个项目加载到内存中并且一次只显示 10 个,因为我认为用户体验会与更快的初始加载相比,更改页面的延迟稍长一些会更好。毕竟,您何时查看 6 个月大的电子邮件?通常的情况是你只关心结果的第一页。类似地,用户可能自上次登录以来进行过多次交互(例如,您在 facebook 上的通知提要),但我再次只想一次加载 n 个结果,但在这种情况下,您可以单击“显示更多”按钮,然后将获取下一个 N 个结果,用另一个“显示更多”链接显示它们,等等,您可以继续单击,直到到达数据集的末尾。我可以想象它们都使用相同的设计,因为它们在技术上都是分页结果,只是具有不同的 UI 输出和流程。

请记住我的数据检索使用的是 NHibernate Queryable 或 Enumerables,任何人都可以就一个好的设计提供一些建议吗?我是否想一次性从数据库中加载所有数据,然后使用交互器模式仅从服务层返回 N 行,将列表的其余部分保持在服务器上的内存中,在用户会话上下文中打开,所以如果我做了另一个调用来检索接下来的 N 行,它将保持原位并继续返回 N 行,直到迭代器完成,或者最好简单地从数据库中检索 N 行并返回那些,在会话上下文中不保存任何内容?我可以看到如何从 Queryable as 返回前 10 个结果

var results = (from email in emails where email.UserId = userId).Take(10);

但我不确定这样做的效率如何,这是最快的方法吗?而且我不知道如何从某个位置开始,这将始终只返回前 10 个,而不是说第二个 10 或第三个 10 等等。

所以我有点不确定最好的方法是如何进行,并希望从做过类似事情的人那里得到一些指示和建议。牢记我的网站性能至关重要,因此用户体验需要非常清晰和互动,并提供令人耳目一新的新结果。基本上,如果您尝试模拟 facebook 新闻提要/墙 - 您将如何使用上述架构实现它?

谢谢!

【问题讨论】:

  • 如果您希望您的系统具有可扩展性,您应该保持您的服务器无状态

标签: c# jquery pagination


【解决方案1】:

您可以将SkipTake 结合使用:

var results = (from email in emails where email.UserId = userId)
              .Skip((currentPage - 1) * 10)
              .Take(10);

关于 Web 服务:您确实应该将其设为无状态 Web 服务。您可以为此使用 ASP.NET Web API。这使您能够构建 RESTful Web 服务。

【讨论】:

  • 感谢您的回复,您知道有什么好的链接可以让我熟悉一下 RESTful Web 服务设计的概述吗?
【解决方案2】:

我想一键加载所有内容吗...

绝对不是,您只想拉下您需要的记录,而不是您可能需要的记录。

...使用交互器模式仅从服务层返回 N 行,保持列表的其余部分保存在服务器上的内存中,在用户会话上下文中打开...

随着这个想法的出现,可扩展性就消失了。

...或者最好从数据库中检索 N 行并返回这些行,在会话上下文中不保留任何内容?

现在你开始走上正轨了……

通常,您希望让数据库尽可能多地进行查询,即您不想访问数据库然后必须进一步查询结果(但是,这并不总是可以避免的)。换句话说,您希望将大部分(如果不是全部)繁重的工作委托给数据库。

您提到您正在使用 NHibernate,它是一个非常强大的 ORM。好消息是,在查询优化/缓存数据等方面为您做了很多工作。像现在的大多数 ORM 一样,NHibernate 对其查询使用延迟执行,所以请注意诸如过早访问数据库和选择何时急切加载数据而不是执行多个查询。 NHibernate 有很多东西要学习,如果您还没有,那么值得花时间在深入了解它之前阅读它,从长远来看,它将为您节省很多麻烦。

牢记我的网站性能至关重要,因此用户体验需要非常清晰和互动,并提供令人耳目一新的新结果

就性能而言(我假设您的意思是页面加载速度),您只想对您的网站进行 ajaxify 处理,即加载页面需要加载的内容,将其余部分拉到后台并动态更新页面。要实现“刷新新结果”部分,您需要查看polling 服务器并拉取新数据。我很确定 Facebook 使用了一种名为 long polling 的技术,它本质上使服务器在一定时间内保持活动请求打开,因此数据似乎“立即”发生。轮询是一个完全不同的球类游戏,它是关于平衡服务器负载与数据需要多么“新鲜” - 这是您需要自己决定的事情,而答案通常取决于数据类型与服务器的硬件能力相比。

【讨论】:

  • 感谢您的回复,这很有帮助。使用 NHibernate,您是否认为总是有空间来实现自己的缓存以提高性能,或者我会在扩展时发现 NHibernate 已经为自己做好了这一切?
  • @user1122909 当然,NHibernate 只会在缓存数据库数据方面有用,您可能希望实现自己的缓存类型,例如页面/视图数据等
【解决方案3】:

那里有一些关于它的链接 (like this),但我喜欢 this guy approach。我不知道我是否会使用他的 PagedQueryable,但他的IPageableIPagedEnumerablePagedEnumerable 真的很有趣。此外,他的项目介绍页面可能会为您提供一些有关如何滚动自己的分页的想法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多