2015-06-26 36 views
1

我正在开发一个使用RavenDB 3的ASP.NET MVC应用程序。我对乌鸦没有太多的经验。Raven以特定方式分页查询

通常,执行查询来显示数据时,页面上会返回前128个项目。通过使用分页查询,可以在“无限滚动”中添加更多记录。

但是,现在我要求项目以“组”的形式加载。

假设下面的类:

public class Item { 
    public string Id { get; set; } 
    public int Group { get; set; } 
    public string text { get; set; } 
} 

假设数据库包含具有组40项= '1',其具有组40项= '2' 和50项具有基团= '3'。

这是一共有130个项目。这意味着最后一个“团队”不会完整。它会缺少2个项目。

我想要一个机制,意识到这一点,以便它将获取至少128 AND将获取'额外',如果最后一个组没有完全包括在内。

之后,当我读取下一页时,我希望它从下一组开始。

有没有什么办法可以让我做这个工作,而不用通过多次调用自己来制作单个页面?

编辑:我不能假定组的大小完全相等,但我可以假设的大小将是“simular”

而且,我不能改变设计来存储所有的项目在一个单一的“group'-对象。

+0

这些组是真的数字吗?如果他们是按顺序加载它们?例如,你的分页总是加载1-3组,而下一页是4-6组? –

+0

@KentCooper:是的,它们是有序的。 – Bjorn

回答

0

好吧,基本上你需要做的是计算前一页中的结果数量和当前页面中的结果数量。下面是一个简单的示例应用程序,让您了解如何做到这一点。需要注意的是,如果当前组范围的结果数量超过MaxNumberOfRequestsPerSession,则会出现错误,因此您可能需要在此处进行一些处理。

运行这个例子

注: 确保您的平台,如果您使用的是最新RavenDB的版本设置在Visual Studio 64。否则,这个例子会抛出一个关于Voron在32位模式下不稳定的错误。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Threading.Tasks; 
using Raven.Client; 
using Raven.Client.Embedded; 
using Raven.Client.Listeners; 

namespace ConsoleApplication 
{ 
    internal class Program 
    { 
     private static void Main(string[] args) 
     { 
      using (var gdm = new GroupDataManager()) 
      { 
       Console.WriteLine("Started Seeding"); 
       gdm.Seed().Wait(); 
       Console.WriteLine("Finished Seeding"); 
       Console.WriteLine("==============================================================="); 
       Console.WriteLine("Get First Page"); 
       Console.WriteLine("==============================================================="); 
       var firstPage = gdm.GetPagedGroupResults(1, 3).Result; 

       foreach (var item in firstPage) 
       { 
        Console.WriteLine(item.Text); 
       } 
       Console.WriteLine("==============================================================="); 
       Console.WriteLine("Get Second Page"); 
       Console.WriteLine("==============================================================="); 
       var secondPage = gdm.GetPagedGroupResults(2, 3).Result; 
       foreach (var item in secondPage) 
       { 
        Console.WriteLine(item.Text); 
       } 
      } 
      Console.ReadLine(); 
     } 
    } 

    public class GroupDataManager : IDisposable 
    { 
     private readonly IDocumentStore _documentStore = new EmbeddedRavenDatabase().Store; 

     public void Dispose() 
     { 
      _documentStore.Dispose(); 
     } 

     public async Task Seed() 
     { 
      var rnd = new Random(); 
      using (var session = _documentStore.OpenAsyncSession()) 
      { 
       for (var groupNumber = 1; groupNumber < 15; groupNumber++) 
       { 
        for (var i = 0; i < rnd.Next(5, 25); i++) 
        { 
         var item = new Item 
         { 
          Group = groupNumber, 
          Text = string.Format("Group: {0} Item:{1}", groupNumber, i) 
         }; 
         await session.StoreAsync(item); 
        } 
       } 

       await session.SaveChangesAsync(); 
      } 
     } 

     public async Task<IList<Item>> GetPagedGroupResults(int page, int numberOfGroupsPerPage) 
     { 
      var startingGroup = ((page - 1) * numberOfGroupsPerPage) + 1; 

      using (var session = _documentStore.OpenAsyncSession()) 
      { 
       // Calculate the number of items that were contained in the previous groups 
       var numberToSkip = await session.Query<Item>().CountAsync(item => item.Group < startingGroup); 

       var endGroup = startingGroup + numberOfGroupsPerPage; 

       // Calculate the number of items that are in the current range of groups 
       var numberToTake = await session.Query<Item>().CountAsync(item => item.Group >= startingGroup && item.Group < endGroup); 

       var results = await session.Query<Item>().Skip(numberToSkip).Take(numberToTake).ToListAsync(); 

       return results; 
      } 
     } 
    } 

    public class Item 
    { 
     public string Id { get; set; } 
     public int Group { get; set; } 
     public string Text { get; set; } 
    } 

    /// <summary> 
    /// For Testing Only. Prevents stale queries 
    /// </summary> 
    public class NoStaleQueriesAllowed : IDocumentQueryListener 
    { 
     public void BeforeQueryExecuted(IDocumentQueryCustomization queryCustomization) 
     { 
      queryCustomization.WaitForNonStaleResults(); 
     } 
    } 

    public class EmbeddedRavenDatabase 
    { 
     private static bool _configured = false; 

     private static readonly Lazy<IDocumentStore> _lazyDocStore = new Lazy<IDocumentStore>(() => 
     { 
      var docStore = new EmbeddableDocumentStore 
      { 
       RunInMemory = true 
      }; 

      docStore.RegisterListener(new NoStaleQueriesAllowed()); 
      docStore.Initialize(); 

      return docStore; 
     }); 

     public IDocumentStore Store 
     { 
      get { return _lazyDocStore.Value; } 
     } 
    } 
} 
+0

这看起来不错!我可以根据我的解决方案。非常感谢你! – Bjorn

+0

谢谢,很高兴我能帮忙! –