├── logo.png ├── msic └── images │ └── icon.png ├── src ├── DotNetCore.Collections.Multi │ ├── DotNetCore.Collections.Multi.csproj │ ├── MultiDictionary.cs │ └── MultiList.cs ├── DotNetCore.Collections.Paginable.Chloe │ ├── DotNetCore │ │ └── Collections │ │ │ └── Paginable │ │ │ ├── Internal │ │ │ ├── ChloeHelper.cs │ │ │ ├── Extensions.Int32.cs │ │ │ ├── ChloeQueryState.cs │ │ │ └── PaginableChloeCollFactory.cs │ │ │ ├── PaginableChloeQuery.cs │ │ │ ├── ChloePage.cs │ │ │ └── Extensions │ │ │ └── SolidPageExtensions.cs │ └── DotNetCore.Collections.Paginable.Chloe.csproj ├── DotNetCore.Collections.Paginable.DosOrm │ ├── DotNetCore │ │ └── Collections │ │ │ └── Paginable │ │ │ ├── Internal │ │ │ ├── DosHelper.cs │ │ │ ├── Extensions.Int32.cs │ │ │ ├── DosQueryState.cs │ │ │ └── PaginableDosCollFactory.cs │ │ │ ├── PaginableDosQuery.cs │ │ │ ├── DosPage.cs │ │ │ └── Extensions │ │ │ └── SolidPageExtensions.cs │ └── DotNetCore.Collections.Paginable.DosOrm.csproj ├── DotNetCore.Collections.Paginable │ ├── DotNetCore │ │ └── Collections │ │ │ └── Paginable │ │ │ ├── Internal │ │ │ ├── Extensions.Int32.cs │ │ │ ├── LimitedMembersTypes.cs │ │ │ ├── PaginableConstants.cs │ │ │ ├── QueryEntryState.cs │ │ │ ├── PageMemberFactory.cs │ │ │ └── PaginableCollectionFactory.cs │ │ │ ├── Abstractions │ │ │ ├── IQueryEntryState`1.cs │ │ │ ├── IPaginable.cs │ │ │ ├── IPaginable`1.cs │ │ │ ├── IPageMember.cs │ │ │ ├── IPage`1.cs │ │ │ └── IPage.cs │ │ │ ├── EmptyPage.cs │ │ │ ├── PaginableSettings.cs │ │ │ ├── PaginableSettingsManager.cs │ │ │ ├── PaginableQueryable.cs │ │ │ ├── PaginableEnumerable.cs │ │ │ ├── PageMember.cs │ │ │ ├── Extensions │ │ │ └── PageExtensions.cs │ │ │ ├── PageMetadata.cs │ │ │ ├── PageBase.cs │ │ │ ├── QueryablePage.cs │ │ │ ├── EnumerablePage.cs │ │ │ └── PaginableSetBase.cs │ └── DotNetCore.Collections.Paginable.csproj ├── DotNetCore.Collections.Paginable.SqlKata │ ├── DotNetCore │ │ └── Collections │ │ │ └── Paginable │ │ │ ├── Internal │ │ │ ├── Extensions.Int32.cs │ │ │ ├── SqlKataHelper.cs │ │ │ ├── SqlKataQueryState.cs │ │ │ └── PaginableSqlKataCollFactory.cs │ │ │ ├── PaginableSqlKataQuery.cs │ │ │ ├── SqlKataPage.cs │ │ │ └── Extensions │ │ │ └── SolidPageExtensions.cs │ └── DotNetCore.Collections.Paginable.SqlKata.csproj ├── DotNetCore.Collections.Paginable.SqlSugar │ ├── DotNetCore │ │ └── Collections │ │ │ └── Paginable │ │ │ ├── Internal │ │ │ ├── Extensions.Int32.cs │ │ │ ├── SqlSugarHelper.cs │ │ │ ├── SqlSugarQueryState.cs │ │ │ └── PaginableSqlSugarCollFactory.cs │ │ │ ├── PaginableSqlSugarQuery.cs │ │ │ ├── SqlSugarPage.cs │ │ │ └── Extensions │ │ │ └── SolidPageExtensions.cs │ └── DotNetCore.Collections.Paginable.SqlSugar.csproj ├── DotNetCore.Collections.Paginable.NHibernate │ ├── DotNetCore │ │ └── Collections │ │ │ └── Paginable │ │ │ ├── Internal │ │ │ ├── Extensions.Int32.cs │ │ │ ├── NhQueryOverHelper.cs │ │ │ ├── NhCoreQueryState.cs │ │ │ └── PaginableNhCoreCollFactory.cs │ │ │ ├── PaginableNhCoreQuery.cs │ │ │ └── NhCorePage.cs │ └── DotNetCore.Collections.Paginable.NHibernate.csproj ├── DotNetCore.Collections.Paginable.FreeSql │ ├── DotNetCore │ │ └── Collections │ │ │ └── Paginable │ │ │ ├── Internal │ │ │ ├── FreeSqlHelper.cs │ │ │ ├── Extensions.Int32.cs │ │ │ ├── FreeSqlQueryState.cs │ │ │ └── PaginableFreeSqlCollFactory.cs │ │ │ ├── PaginableFreeSqlQuery.cs │ │ │ ├── FreeSqlPage.cs │ │ │ └── Extensions │ │ │ └── SolidPageExtensions.cs │ └── DotNetCore.Collections.Paginable.FreeSql.csproj ├── DotNetCore.Collections.Paginable.EntityFrameworkCore │ ├── DotNetCore.Collections.Paginable.EntityFrameworkCore.csproj │ ├── DotNetCore │ │ └── Collections │ │ │ └── Paginable │ │ │ └── SolidPageExtensions.cs │ └── DotNetCore.Collections.Paginable.EntityFrameworkCore.xml ├── DotNetCore.Collections.Paginable.EntityFramework │ ├── DotNetCore.Collections.Paginable.EntityFramework.csproj │ ├── DotNetCore.Collections.Paginable.EntityFramework.xml │ └── DotNetCore │ │ └── Collections │ │ └── Paginable │ │ └── SolidPageExtensions.cs └── DotNetCore.Collections.Paginable.FreeSql.DbContext │ └── DotNetCore.Collections.Paginable.FreeSql.DbContext.csproj ├── tests ├── DotNetCore.Collections.Paginable.Tests │ ├── Models │ │ └── Student.cs │ ├── DotNetCore.Collections.Paginable.Tests.csproj │ └── GetPageForQueryTest.cs ├── DotNetCore.Collections.Paginable.DbTests │ ├── Models │ │ └── Int32Sample.cs │ ├── DotNetCore.Collections.Paginable.DbTests.csproj │ ├── Scripts │ │ └── TestDataScript.sql │ ├── SqlSugarTests.cs │ ├── DosORMTests.cs │ ├── ChloeTests.cs │ ├── SqlKataTests.cs │ ├── EfCoreTests.cs │ └── NhCoreTests.cs └── DotNetCore.Collections.Paginable.ConsoleTests │ ├── DotNetCore.Collections.Paginable.ConsoleTests.csproj │ └── Program.cs ├── performance └── DotNetCore.Collections.Paginable.Benchmarks │ ├── Program.cs │ ├── DotNetCore.Collections.Paginable.Benchmarks.csproj │ └── PaginableBenchmark.cs ├── sample ├── Sample.Ef │ ├── Sample.Ef.csproj │ └── Program.cs ├── Sample │ └── Sample.csproj └── Sample.EfCore │ ├── Sample.EfCore.csproj │ └── Program.cs ├── LICENSE ├── Publish.bat ├── PublishToMyget.bat └── .gitignore /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotnetcore/Collections/HEAD/logo.png -------------------------------------------------------------------------------- /msic/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotnetcore/Collections/HEAD/msic/images/icon.png -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Multi/DotNetCore.Collections.Multi.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /tests/DotNetCore.Collections.Paginable.Tests/Models/Student.cs: -------------------------------------------------------------------------------- 1 | namespace DotNetCore.Collections.Paginable.Tests.Models { 2 | public class Student { 3 | public int Id { get; set; } 4 | public string Name { get; set; } 5 | } 6 | } -------------------------------------------------------------------------------- /performance/DotNetCore.Collections.Paginable.Benchmarks/Program.cs: -------------------------------------------------------------------------------- 1 | using BenchmarkDotNet.Running; 2 | 3 | namespace DotNetCore.Collections.Paginable.Benchmarks { 4 | class Program { 5 | static void Main(string[] args) { 6 | BenchmarkRunner.Run(); 7 | } 8 | } 9 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.Chloe/DotNetCore/Collections/Paginable/Internal/ChloeHelper.cs: -------------------------------------------------------------------------------- 1 | using Chloe; 2 | 3 | namespace DotNetCore.Collections.Paginable.Internal 4 | { 5 | internal static class ChloeHelper 6 | { 7 | public static int Count(IQuery query) => query.Count(); 8 | } 9 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.DosOrm/DotNetCore/Collections/Paginable/Internal/DosHelper.cs: -------------------------------------------------------------------------------- 1 | using Dos.ORM; 2 | 3 | namespace DotNetCore.Collections.Paginable.Internal 4 | { 5 | internal static class DosHelper 6 | { 7 | public static int Count(FromSection query) where T : Entity => query.Count(); 8 | } 9 | } -------------------------------------------------------------------------------- /tests/DotNetCore.Collections.Paginable.DbTests/Models/Int32Sample.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace DotNetCore.Collections.Paginable.DbTests.Models 6 | { 7 | public class Int32Sample 8 | { 9 | public virtual int Id { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable/DotNetCore/Collections/Paginable/Internal/Extensions.Int32.cs: -------------------------------------------------------------------------------- 1 | namespace DotNetCore.Collections.Paginable.Internal 2 | { 3 | internal static class Int32Extensions 4 | { 5 | public static bool IsValid(this int? int32Value) 6 | { 7 | return int32Value is not null; 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.Chloe/DotNetCore/Collections/Paginable/Internal/Extensions.Int32.cs: -------------------------------------------------------------------------------- 1 | namespace DotNetCore.Collections.Paginable.Internal 2 | { 3 | internal static class Int32Extensions 4 | { 5 | public static bool IsValid(this int? int32Value) 6 | { 7 | return int32Value is not null; 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.DosOrm/DotNetCore/Collections/Paginable/Internal/Extensions.Int32.cs: -------------------------------------------------------------------------------- 1 | namespace DotNetCore.Collections.Paginable.Internal 2 | { 3 | internal static class Int32Extensions 4 | { 5 | public static bool IsValid(this int? int32Value) 6 | { 7 | return int32Value is not null; 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.SqlKata/DotNetCore/Collections/Paginable/Internal/Extensions.Int32.cs: -------------------------------------------------------------------------------- 1 | namespace DotNetCore.Collections.Paginable.Internal 2 | { 3 | internal static class Int32Extensions 4 | { 5 | public static bool IsValid(this int? int32Value) 6 | { 7 | return int32Value is not null; 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.SqlSugar/DotNetCore/Collections/Paginable/Internal/Extensions.Int32.cs: -------------------------------------------------------------------------------- 1 | namespace DotNetCore.Collections.Paginable.Internal 2 | { 3 | internal static class Int32Extensions 4 | { 5 | public static bool IsValid(this int? int32Value) 6 | { 7 | return int32Value is not null; 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.NHibernate/DotNetCore/Collections/Paginable/Internal/Extensions.Int32.cs: -------------------------------------------------------------------------------- 1 | namespace DotNetCore.Collections.Paginable.Internal 2 | { 3 | internal static class Int32Extensions 4 | { 5 | public static bool IsValid(this int? int32Value) 6 | { 7 | return int32Value is not null; 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /sample/Sample.Ef/Sample.Ef.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp3.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Multi/MultiDictionary.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace DotNetCore.Collections.Multi 6 | { 7 | // ReSharper disable InconsistentNaming 8 | public class MultiDictionary 9 | { 10 | private readonly List _hashcodeList; 11 | 12 | public MultiDictionary() 13 | { 14 | _hashcodeList = new List(); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.SqlSugar/DotNetCore/Collections/Paginable/Internal/SqlSugarHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using SqlSugar; 3 | 4 | namespace DotNetCore.Collections.Paginable.Internal 5 | { 6 | internal static class SqlSugarHelper 7 | { 8 | public static int Count(ISugarQueryable query) => query.Count(); 9 | 10 | public static Task CountAsync(ISugarQueryable query) => query.CountAsync(); 11 | } 12 | } -------------------------------------------------------------------------------- /sample/Sample/Sample.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | netcoreapp2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.NHibernate/DotNetCore/Collections/Paginable/Internal/NhQueryOverHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using NHibernate; 3 | 4 | namespace DotNetCore.Collections.Paginable.Internal 5 | { 6 | internal static class NhQueryOverHelper 7 | { 8 | public static int Count(IQueryOver queryOver) => queryOver.RowCount(); 9 | public static Task CountAsync(IQueryOver queryOver) => queryOver.RowCountAsync(); 10 | } 11 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.FreeSql/DotNetCore/Collections/Paginable/Internal/FreeSqlHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using FreeSql; 3 | 4 | namespace DotNetCore.Collections.Paginable.Internal 5 | { 6 | internal static class FreeSqlHelper 7 | { 8 | public static long Count(ISelect select) where T : class => select.Count(); 9 | 10 | public static Task CountAsync(ISelect select) where T : class => select.CountAsync(); 11 | } 12 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.SqlKata/DotNetCore/Collections/Paginable/Internal/SqlKataHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using SqlKata; 3 | using SqlKata.Execution; 4 | 5 | namespace DotNetCore.Collections.Paginable.Internal 6 | { 7 | internal static class SqlKataHelper 8 | { 9 | public static int Count(Query query) => query.Clone().Count(null); 10 | 11 | public static Task CountAsync(Query query) => query.Clone().CountAsync(null); 12 | } 13 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable/DotNetCore/Collections/Paginable/Internal/LimitedMembersTypes.cs: -------------------------------------------------------------------------------- 1 | namespace DotNetCore.Collections.Paginable.Internal 2 | { 3 | /// 4 | /// Limited members type 5 | /// 6 | public enum LimitedMembersTypes 7 | { 8 | /// 9 | /// Unlimited 10 | /// 11 | Unlimited = 0, 12 | 13 | /// 14 | /// Customize 15 | /// 16 | Customize = 1, 17 | } 18 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.FreeSql/DotNetCore/Collections/Paginable/Internal/Extensions.Int32.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DotNetCore.Collections.Paginable.Internal 4 | { 5 | internal static class Int32Extensions 6 | { 7 | public static bool IsValid(this int? int32Value) 8 | { 9 | return int32Value is not null; 10 | } 11 | 12 | public static int AsInt32(this long int64) 13 | { 14 | return Convert.ToInt32(int64); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /sample/Sample.EfCore/Sample.EfCore.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp2.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable/DotNetCore/Collections/Paginable/Abstractions/IQueryEntryState`1.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace DotNetCore.Collections.Paginable.Abstractions 4 | { 5 | /// 6 | /// Query entry state interface 7 | /// 8 | /// 9 | public interface IQueryEntryState 10 | { 11 | /// 12 | /// Gets all values 13 | /// 14 | IEnumerable AllValues { get; } 15 | } 16 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable/DotNetCore/Collections/Paginable/EmptyPage.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | 3 | namespace DotNetCore.Collections.Paginable 4 | { 5 | /// 6 | /// Empty page 7 | /// 8 | /// 9 | public class EmptyPage : EnumerablePage 10 | { 11 | /// 12 | /// Create a new instance of 13 | /// 14 | public EmptyPage() : base(Enumerable.Empty(), 1, 0, 0) { } 15 | } 16 | } -------------------------------------------------------------------------------- /tests/DotNetCore.Collections.Paginable.ConsoleTests/DotNetCore.Collections.Paginable.ConsoleTests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | netcoreapp3.1 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable/DotNetCore/Collections/Paginable/Internal/PaginableConstants.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable InconsistentNaming 2 | 3 | namespace DotNetCore.Collections.Paginable.Internal 4 | { 5 | internal static class PaginableConstants 6 | { 7 | /// 8 | /// Default page size 9 | /// 10 | public const int DEFAULT_PAGE_SIZE = 50; 11 | 12 | /// 13 | /// Max member items support 14 | /// 15 | public const long MAX_MEMBER_ITEMS_SUPPORT = 1000 * 10000; 16 | } 17 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable/DotNetCore.Collections.Paginable.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | net5.0;netstandard2.1;net461;net451 7 | 8 | 9 | 10 | DotNetCore.Collections.Paginable 11 | DotNetCore.Collections.Paginable 12 | Paginable extension for collection. 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable/DotNetCore/Collections/Paginable/Abstractions/IPaginable.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | 3 | // ReSharper disable once CheckNamespace 4 | namespace DotNetCore.Collections.Paginable 5 | { 6 | /// 7 | /// Paginable interface 8 | /// 9 | public interface IPaginable : IEnumerable 10 | { 11 | /// 12 | /// Gets page size 13 | /// 14 | int PageSize { get; } 15 | 16 | /// 17 | /// Gets member count 18 | /// 19 | int MemberCount { get; } 20 | } 21 | } -------------------------------------------------------------------------------- /performance/DotNetCore.Collections.Paginable.Benchmarks/DotNetCore.Collections.Paginable.Benchmarks.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | netcoreapp3.1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable/DotNetCore/Collections/Paginable/Abstractions/IPaginable`1.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | // ReSharper disable once CheckNamespace 4 | namespace DotNetCore.Collections.Paginable 5 | { 6 | /// 7 | /// Paginable interface 8 | /// 9 | /// 10 | public interface IPaginable : IEnumerable>, IPaginable 11 | { 12 | /// 13 | /// Get page 14 | /// 15 | /// Page number 16 | /// 17 | IPage GetPage(int pageNumber); 18 | } 19 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable/DotNetCore/Collections/Paginable/PaginableSettings.cs: -------------------------------------------------------------------------------- 1 | using DotNetCore.Collections.Paginable.Internal; 2 | 3 | namespace DotNetCore.Collections.Paginable 4 | { 5 | /// 6 | /// Paginable settings 7 | /// 8 | public class PaginableSettings 9 | { 10 | /// 11 | /// Gets or sets default page size 12 | /// 13 | public int DefaultPageSize { get; set; } = PaginableConstants.DEFAULT_PAGE_SIZE; 14 | 15 | /// 16 | /// Gets or sets max member items 17 | /// 18 | public long MaxMemberItems { get; set; } = PaginableConstants.MAX_MEMBER_ITEMS_SUPPORT; 19 | } 20 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable/DotNetCore/Collections/Paginable/Abstractions/IPageMember.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable once CheckNamespace 2 | 3 | namespace DotNetCore.Collections.Paginable 4 | { 5 | /// 6 | /// Page member wrapper interface 7 | /// 8 | /// 9 | public interface IPageMember 10 | { 11 | /// 12 | /// Gets value of current member 13 | /// 14 | T Value { get; } 15 | 16 | /// 17 | /// Gets offset of current member 18 | /// 19 | int Offset { get; } 20 | 21 | /// 22 | /// Gets item number of current member 23 | /// 24 | int ItemNumber { get; } 25 | } 26 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable/DotNetCore/Collections/Paginable/Abstractions/IPage`1.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | // ReSharper disable once CheckNamespace 4 | namespace DotNetCore.Collections.Paginable 5 | { 6 | /// 7 | /// Page interface 8 | /// 9 | /// 10 | public interface IPage : IEnumerable>, IPage 11 | { 12 | /// 13 | /// Gets page member indexer 14 | /// 15 | /// Index 16 | IPageMember this[int index] { get; } 17 | 18 | /// 19 | /// Convert to original items 20 | /// 21 | /// 22 | IEnumerable ToOriginalItems(); 23 | } 24 | } -------------------------------------------------------------------------------- /tests/DotNetCore.Collections.Paginable.Tests/DotNetCore.Collections.Paginable.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netcoreapp3.1 4 | false 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.DosOrm/DotNetCore.Collections.Paginable.DosOrm.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | net5.0;netstandard2.1;net461;net451 7 | 8 | 9 | 10 | DotNetCore.Collections.Paginable.DosORM 11 | DotNetCore.Collections.Paginable.DosORM 12 | Paginable extension with Dos.ORM for collection. 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.FreeSql/DotNetCore.Collections.Paginable.FreeSql.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | net5.0;netstandard2.1;net461;net451 7 | 8 | 9 | 10 | DotNetCore.Collections.Paginable.FreeSql 11 | DotNetCore.Collections.Paginable.FreeSql 12 | Paginable extension with NCC FreeSql for collection. 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.NHibernate/DotNetCore.Collections.Paginable.NHibernate.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | net5.0;netstandard2.1;net461 7 | 8 | 9 | 10 | DotNetCore.Collections.Paginable.NHibernate 11 | DotNetCore.Collections.Paginable.NHibernate 12 | Paginable extension with NHibernate for collection. 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.Chloe/DotNetCore.Collections.Paginable.Chloe.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | net5.0;netstandard2.1;net461;net451 7 | 8 | 9 | 10 | DotNetCore.Collections.Paginable.Chloe 11 | DotNetCore.Collections.Paginable.Chloe 12 | Paginable extension with Chloe for collection. 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.EntityFrameworkCore/DotNetCore.Collections.Paginable.EntityFrameworkCore.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | net5.0;netstandard2.1 7 | 8 | 9 | 10 | DotNetCore.Collections.Paginable.EntityFrameworkCore 11 | DotNetCore.Collections.Paginable.EntityFrameworkCore 12 | Paginable extension with Microsoft EntityFrameworkCore for collection. 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.EntityFramework/DotNetCore.Collections.Paginable.EntityFramework.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | net5.0;netstandard2.1;net461;net451 7 | 8 | 9 | 10 | DotNetCore.Collections.Paginable.EntityFramework 11 | DotNetCore.Collections.Paginable.EntityFramework 12 | Paginable extension with Microsoft EntityFramework for collection. 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.FreeSql.DbContext/DotNetCore.Collections.Paginable.FreeSql.DbContext.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | net5.0;netstandard2.1;net461;net451 7 | 8 | 9 | 10 | DotNetCore.Collections.Paginable.FreeSql.DbContext 11 | DotNetCore.Collections.Paginable.FreeSql.DbContext 12 | Paginable extension with NCC FreeSql with DbContext for collection. 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable/DotNetCore/Collections/Paginable/PaginableSettingsManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace DotNetCore.Collections.Paginable 4 | { 5 | /// 6 | /// Paginable settings manager 7 | /// 8 | public static class PaginableSettingsManager 9 | { 10 | // ReSharper disable once InconsistentNaming 11 | private static PaginableSettings _settingsCache { get; set; } 12 | 13 | static PaginableSettingsManager() 14 | => _settingsCache = new PaginableSettings(); 15 | 16 | /// 17 | /// Get paginable settings 18 | /// 19 | public static PaginableSettings Settings 20 | => _settingsCache; 21 | 22 | /// 23 | /// Update paginable settings 24 | /// 25 | /// 26 | public static void UpdateSettings(PaginableSettings settings) 27 | => _settingsCache = settings ?? throw new ArgumentNullException(nameof(settings)); 28 | } 29 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 AlexLEWIS 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.SqlKata/DotNetCore.Collections.Paginable.SqlKata.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | net5.0;netstandard2.1;net461;net451 7 | 8 | 9 | 10 | DotNetCore.Collections.Paginable.SqlKata 11 | DotNetCore.Collections.Paginable.SqlKata 12 | Paginable extension with SqlKata for collection. 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.SqlSugar/DotNetCore.Collections.Paginable.SqlSugar.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | net5.0;netstandard2.1;net461;net451 7 | 8 | 9 | 10 | DotNetCore.Collections.Paginable.SqlSugar 11 | DotNetCore.Collections.Paginable.SqlSugar 12 | Paginable extension with SqlSugar for collection. 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Publish.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | if not exist nuget_pub ( 3 | md nuget_pub 4 | ) 5 | 6 | for /R "nuget_pub" %%s in (*) do ( 7 | del "%%s" 8 | ) 9 | 10 | set /p key=input key: 11 | 12 | ::Paginable 13 | dotnet pack src/DotNetCore.Collections.Paginable -c Release -o nuget_pub 14 | dotnet pack src/DotNetCore.Collections.Paginable.Chloe -c Release -o nuget_pub 15 | dotnet pack src/DotNetCore.Collections.Paginable.DosOrm -c Release -o nuget_pub 16 | dotnet pack src/DotNetCore.Collections.Paginable.EntityFramework -c Release -o nuget_pub 17 | dotnet pack src/DotNetCore.Collections.Paginable.EntityFrameworkCore -c Release -o nuget_pub 18 | dotnet pack src/DotNetCore.Collections.Paginable.FreeSql -c Release -o nuget_pub 19 | dotnet pack src/DotNetCore.Collections.Paginable.FreeSql.DbContext -c Release -o nuget_pub 20 | dotnet pack src/DotNetCore.Collections.Paginable.NHibernate -c Release -o nuget_pub 21 | dotnet pack src/DotNetCore.Collections.Paginable.SqlKata -c Release -o nuget_pub 22 | dotnet pack src/DotNetCore.Collections.Paginable.SqlSugar -c Release -o nuget_pub 23 | 24 | for /R "nuget_pub" %%s in (*symbols.nupkg) do ( 25 | del "%%s" 26 | ) 27 | 28 | echo. 29 | echo. 30 | 31 | set source=https://www.nuget.org/api/v2/package 32 | 33 | for /R "nuget_pub" %%s in (*.nupkg) do ( 34 | call nuget push "%%s" %key% -Source %source% 35 | echo. 36 | ) 37 | 38 | pause -------------------------------------------------------------------------------- /PublishToMyget.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | if not exist nuget_pub ( 3 | md nuget_pub 4 | ) 5 | 6 | for /R "nuget_pub" %%s in (*) do ( 7 | del "%%s" 8 | ) 9 | 10 | set /p key=input key: 11 | 12 | ::Paginable 13 | dotnet pack src/DotNetCore.Collections.Paginable -c Release -o nuget_pub 14 | dotnet pack src/DotNetCore.Collections.Paginable.Chloe -c Release -o nuget_pub 15 | dotnet pack src/DotNetCore.Collections.Paginable.DosOrm -c Release -o nuget_pub 16 | dotnet pack src/DotNetCore.Collections.Paginable.EntityFramework -c Release -o nuget_pub 17 | dotnet pack src/DotNetCore.Collections.Paginable.EntityFrameworkCore -c Release -o nuget_pub 18 | dotnet pack src/DotNetCore.Collections.Paginable.FreeSql -c Release -o nuget_pub 19 | dotnet pack src/DotNetCore.Collections.Paginable.FreeSql.DbContext -c Release -o nuget_pub 20 | dotnet pack src/DotNetCore.Collections.Paginable.NHibernate -c Release -o nuget_pub 21 | dotnet pack src/DotNetCore.Collections.Paginable.SqlKata -c Release -o nuget_pub 22 | dotnet pack src/DotNetCore.Collections.Paginable.SqlSugar -c Release -o nuget_pub 23 | 24 | for /R "nuget_pub" %%s in (*symbols.nupkg) do ( 25 | del "%%s" 26 | ) 27 | 28 | echo. 29 | echo. 30 | 31 | set source=https://www.myget.org/F/alexinea/api/v2/package 32 | 33 | for /R "nuget_pub" %%s in (*.nupkg) do ( 34 | call nuget push "%%s" %key% -Source %source% 35 | echo. 36 | ) 37 | 38 | pause -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.SqlKata/DotNetCore/Collections/Paginable/PaginableSqlKataQuery.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SqlKata; 3 | 4 | namespace DotNetCore.Collections.Paginable 5 | { 6 | /// 7 | /// SqlKataPage collection 8 | /// 9 | /// 10 | public class PaginableSqlKataQuery : PaginableSetBase 11 | { 12 | private readonly Query _sqlKataQuery; 13 | 14 | // ReSharper disable once UnusedMember.Local 15 | private PaginableSqlKataQuery() { } 16 | 17 | internal PaginableSqlKataQuery(Query query, int pageSize, int realPageCount, int realMemberCount) 18 | : base(pageSize, realPageCount, realMemberCount) 19 | { 20 | _sqlKataQuery = query; 21 | } 22 | 23 | internal PaginableSqlKataQuery(Query query, int pageSize, int realPageCount, int realMemberCount, int limitedMembersCount) 24 | : base(pageSize, realPageCount, realMemberCount, limitedMembersCount) 25 | { 26 | _sqlKataQuery = query; 27 | } 28 | 29 | /// 30 | protected override Lazy> GetSpecifiedPage(int currentPageNumber, int pageSize, int realMemberCount) 31 | { 32 | return new(() => new SqlKataPage(_sqlKataQuery, currentPageNumber, pageSize, realMemberCount)); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.SqlSugar/DotNetCore/Collections/Paginable/PaginableSqlSugarQuery.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SqlSugar; 3 | 4 | namespace DotNetCore.Collections.Paginable 5 | { 6 | /// 7 | /// SqlSugarPage collection 8 | /// 9 | public class PaginableSqlSugarQuery : PaginableSetBase 10 | { 11 | private readonly ISugarQueryable _sqlSugarQuery; 12 | 13 | // ReSharper disable once UnusedMember.Local 14 | private PaginableSqlSugarQuery() { } 15 | 16 | internal PaginableSqlSugarQuery(ISugarQueryable select, int pageSize, int realPageCount, int realMemberCount) 17 | : base(pageSize, realPageCount, realMemberCount) 18 | { 19 | _sqlSugarQuery = select; 20 | } 21 | 22 | internal PaginableSqlSugarQuery(ISugarQueryable select, int pageSize, int realPageCount, int realMemberCount, int limitedMembersCount) 23 | : base(pageSize, realPageCount, realMemberCount, limitedMembersCount) 24 | { 25 | _sqlSugarQuery = select; 26 | } 27 | 28 | /// 29 | protected override Lazy> GetSpecifiedPage(int currentPageNumber, int pageSize, int realMemberCount) 30 | { 31 | return new(() => new SqlSugarPage(_sqlSugarQuery, currentPageNumber, pageSize, realMemberCount)); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.NHibernate/DotNetCore/Collections/Paginable/PaginableNhCoreQuery.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NHibernate; 3 | 4 | namespace DotNetCore.Collections.Paginable 5 | { 6 | /// 7 | /// NHibernatePage collection 8 | /// 9 | public class PaginableNhCoreQuery : PaginableSetBase 10 | { 11 | private readonly IQueryOver _nhibernateQueryOver; 12 | 13 | // ReSharper disable once UnusedMember.Local 14 | private PaginableNhCoreQuery() { } 15 | 16 | internal PaginableNhCoreQuery(IQueryOver queryOver, int pageSize, int realPageCount, int realMemberCount) 17 | : base(pageSize, realPageCount, realMemberCount) 18 | { 19 | _nhibernateQueryOver = queryOver; 20 | } 21 | 22 | internal PaginableNhCoreQuery(IQueryOver select, int pageSize, int realPageCount, int realMemberCount, int limitedMembersCount) 23 | : base(pageSize, realPageCount, realMemberCount, limitedMembersCount) 24 | { 25 | _nhibernateQueryOver = select; 26 | } 27 | 28 | /// 29 | protected override Lazy> GetSpecifiedPage(int currentPageNumber, int pageSize, int realMemberCount) 30 | { 31 | return new(() => new NhCorePage(_nhibernateQueryOver, currentPageNumber, pageSize, realMemberCount)); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable/DotNetCore/Collections/Paginable/Internal/QueryEntryState.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using DotNetCore.Collections.Paginable.Abstractions; 5 | 6 | namespace DotNetCore.Collections.Paginable.Internal 7 | { 8 | /// 9 | /// Query entry state 10 | /// 11 | /// 12 | internal class QueryEntryState : IQueryEntryState 13 | { 14 | private readonly Lazy> _mLazyQueryableMembers; 15 | 16 | /// 17 | /// Query entry state 18 | /// 19 | /// Orgin queryable result 20 | /// skip number 21 | /// take number 22 | public QueryEntryState(IQueryable queryable, int skip, int take) 23 | { 24 | if (skip < 0) 25 | throw new ArgumentOutOfRangeException(nameof(skip), $"{nameof(skip)} can not be less than zero"); 26 | 27 | if (take < 0) 28 | throw new ArgumentOutOfRangeException(nameof(take), $"{nameof(take)} can not be less than zero"); 29 | 30 | _mLazyQueryableMembers = new Lazy>(() => queryable.Skip(skip).Take(take).AsEnumerable()); 31 | } 32 | 33 | /// 34 | /// Get all value. 35 | /// 36 | public IEnumerable AllValues => _mLazyQueryableMembers.Value; 37 | } 38 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable/DotNetCore/Collections/Paginable/Abstractions/IPage.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | 3 | // ReSharper disable once CheckNamespace 4 | namespace DotNetCore.Collections.Paginable 5 | { 6 | /// 7 | /// Page interface 8 | /// 9 | public interface IPage : IEnumerable 10 | { 11 | /// 12 | /// Gets total page count 13 | /// 14 | int TotalPageCount { get; } 15 | 16 | /// 17 | /// Gets total member count 18 | /// 19 | int TotalMemberCount { get; } 20 | 21 | /// 22 | /// Gets current page number 23 | /// 24 | int CurrentPageNumber { get; } 25 | 26 | /// 27 | /// Gets page size 28 | /// 29 | int PageSize { get; } 30 | 31 | /// 32 | /// Gets current page size, may equal to or less than page size. 33 | /// 34 | int CurrentPageSize { get; } 35 | 36 | /// 37 | /// Has previous. If this page is the first page, then returns false. 38 | /// 39 | bool HasPrevious { get; } 40 | 41 | /// 42 | /// Has next. If this page is the last page, then returns false. 43 | /// 44 | bool HasNext { get; } 45 | 46 | /// 47 | /// Get metadata of page 48 | /// 49 | /// 50 | PageMetadata GetMetadata(); 51 | } 52 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.FreeSql/DotNetCore/Collections/Paginable/PaginableFreeSqlQuery.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using FreeSql; 3 | 4 | namespace DotNetCore.Collections.Paginable 5 | { 6 | /// 7 | /// FreeSqlPage collection 8 | /// 9 | public class PaginableFreeSqlQuery : PaginableSetBase where T : class 10 | { 11 | private readonly ISelect _freeSqlQuery; 12 | private readonly bool _includeNestedMembers; 13 | 14 | // ReSharper disable once UnusedMember.Local 15 | private PaginableFreeSqlQuery() { } 16 | 17 | internal PaginableFreeSqlQuery(ISelect select, int pageSize, int realPageCount, int realMemberCount, bool includeNestedMembers) 18 | : base(pageSize, realPageCount, realMemberCount) 19 | { 20 | _freeSqlQuery = select; 21 | _includeNestedMembers = includeNestedMembers; 22 | } 23 | 24 | internal PaginableFreeSqlQuery(ISelect select, int pageSize, int realPageCount, int realMemberCount, int limitedMembersCount, bool includeNestedMembers) 25 | : base(pageSize, realPageCount, realMemberCount, limitedMembersCount) 26 | { 27 | _freeSqlQuery = select; 28 | _includeNestedMembers = includeNestedMembers; 29 | } 30 | 31 | /// 32 | protected override Lazy> GetSpecifiedPage(int currentPageNumber, int pageSize, int realMemberCount) 33 | { 34 | return new(() => new FreeSqlPage(_freeSqlQuery, currentPageNumber, pageSize, realMemberCount, _includeNestedMembers)); 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable/DotNetCore/Collections/Paginable/PaginableQueryable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | 4 | namespace DotNetCore.Collections.Paginable 5 | { 6 | /// 7 | /// QueryablePage collection 8 | /// 9 | /// 10 | public class PaginableQueryable : PaginableSetBase 11 | { 12 | private readonly IQueryable _queryable; 13 | 14 | // ReSharper disable once UnusedMember.Local 15 | private PaginableQueryable() { } 16 | 17 | internal PaginableQueryable(IQueryable queryable, int pageSize, int realPageCount, int realMemberCount) 18 | : base(pageSize, realPageCount, realMemberCount) 19 | { 20 | _queryable = queryable; 21 | } 22 | 23 | internal PaginableQueryable(IQueryable queryable, int pageSize, int realPageCount, int realMemberCount, int limitedMembersCount) 24 | : base(pageSize, realPageCount, realMemberCount, limitedMembersCount) 25 | { 26 | _queryable = queryable; 27 | } 28 | 29 | /// 30 | /// Get special page 31 | /// 32 | /// 33 | /// 34 | /// 35 | /// 36 | protected override Lazy> GetSpecifiedPage(int currentPageNumber, int pageSize, int realMemberCount) 37 | { 38 | return new(() => new EnumerablePage(_queryable, currentPageNumber, pageSize, realMemberCount)); 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.NHibernate/DotNetCore/Collections/Paginable/Internal/NhCoreQueryState.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using DotNetCore.Collections.Paginable.Abstractions; 4 | using NHibernate; 5 | 6 | namespace DotNetCore.Collections.Paginable.Internal 7 | { 8 | /// 9 | /// NHibernate query state 10 | /// 11 | /// 12 | public class NhCoreQueryState : IQueryEntryState 13 | { 14 | private readonly Lazy> _mLazyChloeQueryMembers; 15 | 16 | /// 17 | /// NHibernate query state 18 | /// 19 | /// 20 | /// 21 | /// 22 | public NhCoreQueryState(IQueryOver queryOver, int skip, int pageSize) 23 | { 24 | if (queryOver is null) 25 | throw new ArgumentNullException(nameof(queryOver)); 26 | 27 | if (skip < 0) 28 | throw new ArgumentOutOfRangeException(nameof(skip), $"{nameof(skip)} can not be less than zero"); 29 | 30 | if (pageSize < 0) 31 | throw new ArgumentOutOfRangeException(nameof(pageSize), $"{nameof(pageSize)} can not be less than zero"); 32 | 33 | _mLazyChloeQueryMembers = new Lazy>(() => queryOver.Skip(skip).Take(pageSize).Future()); 34 | } 35 | 36 | /// 37 | /// Get all value. 38 | /// 39 | public IEnumerable AllValues => _mLazyChloeQueryMembers.Value.GetEnumerable(); 40 | } 41 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.Chloe/DotNetCore/Collections/Paginable/PaginableChloeQuery.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Chloe; 3 | 4 | namespace DotNetCore.Collections.Paginable 5 | { 6 | /// 7 | /// ChloePage collection 8 | /// 9 | public class PaginableChloeQuery : PaginableSetBase 10 | { 11 | private readonly IQuery _chloeQuery; 12 | private readonly Func, IQuery> _additionalQueryFunc; 13 | 14 | // ReSharper disable once UnusedMember.Local 15 | private PaginableChloeQuery() { } 16 | 17 | internal PaginableChloeQuery(IQuery select, int pageSize, int realPageCount, int realMemberCount, Func, IQuery> additionalQueryFunc = null) 18 | : base(pageSize, realPageCount, realMemberCount) 19 | { 20 | _chloeQuery = select; 21 | _additionalQueryFunc = additionalQueryFunc; 22 | } 23 | 24 | internal PaginableChloeQuery(IQuery select, int pageSize, int realPageCount, int realMemberCount, int limitedMembersCount, 25 | Func, IQuery> additionalQueryFunc = null) 26 | : base(pageSize, realPageCount, realMemberCount, limitedMembersCount) 27 | { 28 | _chloeQuery = select; 29 | _additionalQueryFunc = additionalQueryFunc; 30 | } 31 | 32 | /// 33 | protected override Lazy> GetSpecifiedPage(int currentPageNumber, int pageSize, int realMemberCount) 34 | { 35 | return new(() => new ChloePage(_chloeQuery, currentPageNumber, pageSize, realMemberCount, _additionalQueryFunc)); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable/DotNetCore/Collections/Paginable/PaginableEnumerable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace DotNetCore.Collections.Paginable 5 | { 6 | /// 7 | /// EnumerablePage collection 8 | /// 9 | /// 10 | public class PaginableEnumerable : PaginableSetBase 11 | { 12 | private readonly IEnumerable _enumerable; 13 | 14 | // ReSharper disable once UnusedMember.Local 15 | private PaginableEnumerable() { } 16 | 17 | internal PaginableEnumerable(IEnumerable enumerable, int pageSize, int realPageCount, int realMemberCount) 18 | : base(pageSize, realPageCount, realMemberCount) 19 | { 20 | _enumerable = enumerable; 21 | } 22 | 23 | internal PaginableEnumerable(IEnumerable enumerable, int pageSize, int realPageCount, int realMemberCount, int limitedMembersCount) 24 | : base(pageSize, realPageCount, realMemberCount, limitedMembersCount) 25 | { 26 | _enumerable = enumerable; 27 | } 28 | 29 | /// 30 | /// Get special page 31 | /// 32 | /// 33 | /// 34 | /// 35 | /// 36 | protected override Lazy> GetSpecifiedPage(int currentPageNumber, int pageSize, int realMemberCount) 37 | { 38 | return new(() => new EnumerablePage(_enumerable, currentPageNumber, pageSize, realMemberCount)); 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.SqlSugar/DotNetCore/Collections/Paginable/Internal/SqlSugarQueryState.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using DotNetCore.Collections.Paginable.Abstractions; 4 | using SqlSugar; 5 | 6 | namespace DotNetCore.Collections.Paginable.Internal 7 | { 8 | /// 9 | /// SqlSugar query state 10 | /// 11 | /// 12 | public class SqlSugarQueryState : IQueryEntryState 13 | { 14 | private readonly Lazy> _mLazySqlSugarQueryMembers; 15 | 16 | /// 17 | /// SqlSugar query state 18 | /// 19 | /// 20 | /// 21 | /// 22 | public SqlSugarQueryState(ISugarQueryable query, int currentPageNumber, int pageSize) 23 | { 24 | if (query is null) 25 | throw new ArgumentNullException(nameof(query)); 26 | 27 | if (currentPageNumber < 0) 28 | throw new ArgumentOutOfRangeException(nameof(currentPageNumber), $"{nameof(currentPageNumber)} can not be less than zero"); 29 | 30 | if (pageSize < 0) 31 | throw new ArgumentOutOfRangeException(nameof(pageSize), $"{nameof(pageSize)} can not be less than zero"); 32 | 33 | _mLazySqlSugarQueryMembers = new Lazy>(() => query.ToPageList(currentPageNumber, pageSize)); 34 | } 35 | 36 | /// 37 | /// Get all value. 38 | /// 39 | public IEnumerable AllValues => _mLazySqlSugarQueryMembers.Value; 40 | } 41 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.SqlKata/DotNetCore/Collections/Paginable/Internal/SqlKataQueryState.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using DotNetCore.Collections.Paginable.Abstractions; 4 | using SqlKata; 5 | using SqlKata.Execution; 6 | 7 | namespace DotNetCore.Collections.Paginable.Internal 8 | { 9 | /// 10 | /// SqlKata query state 11 | /// 12 | /// 13 | internal class SqlKataQueryState : IQueryEntryState 14 | { 15 | private readonly Lazy> _mLazySqlKataQueryMembers; 16 | 17 | /// 18 | /// SqlKata query state 19 | /// 20 | /// 21 | /// 22 | /// 23 | public SqlKataQueryState(Query query, int currentPageNumber, int pageSize) 24 | { 25 | if (query is null) 26 | throw new ArgumentNullException(nameof(query)); 27 | 28 | if (currentPageNumber < 0) 29 | throw new ArgumentOutOfRangeException(nameof(currentPageNumber), $"{nameof(currentPageNumber)} can not be less than zero"); 30 | 31 | if (pageSize < 0) 32 | throw new ArgumentOutOfRangeException(nameof(pageSize), $"{nameof(pageSize)} can not be less than zero"); 33 | 34 | _mLazySqlKataQueryMembers = new Lazy>(() => query.ForPage(currentPageNumber, pageSize).Get()); 35 | } 36 | 37 | /// 38 | /// Get all value. 39 | /// 40 | public IEnumerable AllValues => _mLazySqlKataQueryMembers.Value; 41 | } 42 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.DosOrm/DotNetCore/Collections/Paginable/PaginableDosQuery.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Dos.ORM; 3 | 4 | namespace DotNetCore.Collections.Paginable 5 | { 6 | /// 7 | /// DosPage collection 8 | /// 9 | public class PaginableDosQuery : PaginableSetBase where T : Entity 10 | { 11 | private readonly FromSection _dosOrmQuery; 12 | 13 | private readonly Func, FromSection> _additionalQueryFunc; 14 | 15 | // ReSharper disable once UnusedMember.Local 16 | private PaginableDosQuery() { } 17 | 18 | internal PaginableDosQuery(FromSection select, int pageSize, int realPageCount, int realMemberCount, Func, FromSection> additionalQueryFunc = null) 19 | : base(pageSize, realPageCount, realMemberCount) 20 | { 21 | _dosOrmQuery = select; 22 | _additionalQueryFunc = additionalQueryFunc; 23 | } 24 | 25 | internal PaginableDosQuery(FromSection select, int pageSize, int realPageCount, int realMemberCount, int limitedMembersCount, 26 | Func, FromSection> additionalQueryFunc = null) 27 | : base(pageSize, realPageCount, realMemberCount, limitedMembersCount) 28 | { 29 | _dosOrmQuery = select; 30 | _additionalQueryFunc = additionalQueryFunc; 31 | } 32 | 33 | /// 34 | protected override Lazy> GetSpecifiedPage(int currentPageNumber, int pageSize, int realMemberCount) 35 | { 36 | return new(() => new DosPage(_dosOrmQuery, currentPageNumber, pageSize, realMemberCount, _additionalQueryFunc)); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable/DotNetCore/Collections/Paginable/PageMember.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using DotNetCore.Collections.Paginable.Abstractions; 4 | 5 | namespace DotNetCore.Collections.Paginable 6 | { 7 | /// 8 | /// Page member 9 | /// 10 | /// 11 | public struct PageMember : IPageMember 12 | { 13 | private readonly T _memberValue; 14 | private readonly int _offset; 15 | private readonly int _startIndex; 16 | private readonly IQueryEntryState _state; 17 | 18 | internal PageMember(T memberValue, int offset, ref int startIndex) 19 | { 20 | if (offset < 0) 21 | throw new ArgumentOutOfRangeException(nameof(offset), "offset can not be less than zero."); 22 | _startIndex = startIndex; 23 | _memberValue = memberValue; 24 | _offset = offset; 25 | _state = null; 26 | } 27 | 28 | internal PageMember(IQueryEntryState state, int offset, ref int startIndex) 29 | { 30 | if (offset < 0) 31 | throw new ArgumentOutOfRangeException(nameof(offset), "offset can not be less than zero."); 32 | _startIndex = startIndex; 33 | _memberValue = default; 34 | _offset = offset; 35 | _state = state; 36 | } 37 | 38 | /// 39 | public T Value => _state is null 40 | ? _memberValue 41 | : _state.AllValues.ElementAt(_offset); 42 | 43 | /// 44 | public int Offset => _offset; 45 | 46 | /// 47 | public int ItemNumber => _startIndex + _offset + 1; 48 | } 49 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.FreeSql/DotNetCore/Collections/Paginable/Internal/FreeSqlQueryState.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using DotNetCore.Collections.Paginable.Abstractions; 4 | using FreeSql; 5 | 6 | namespace DotNetCore.Collections.Paginable.Internal 7 | { 8 | /// 9 | /// FreeSql query state 10 | /// 11 | /// 12 | public class FreeSqlQueryState : IQueryEntryState where T : class 13 | { 14 | private readonly Lazy> _mLazyFreeSqlQueryMembers; 15 | 16 | /// 17 | /// FreeSql query state 18 | /// 19 | /// 20 | /// 21 | /// 22 | /// 23 | public FreeSqlQueryState(ISelect select, int currentPageNumber, int pageSize, bool includeNestedMembers) 24 | { 25 | if (select is null) 26 | throw new ArgumentNullException(nameof(select)); 27 | 28 | if (currentPageNumber < 0) 29 | throw new ArgumentOutOfRangeException(nameof(currentPageNumber), $"{nameof(currentPageNumber)} can not be less than zero"); 30 | 31 | if (pageSize < 0) 32 | throw new ArgumentOutOfRangeException(nameof(pageSize), $"{nameof(pageSize)} can not be less than zero"); 33 | 34 | _mLazyFreeSqlQueryMembers = new Lazy>(() => select.Page(currentPageNumber, pageSize).ToList(includeNestedMembers)); 35 | } 36 | 37 | /// 38 | /// Get all value. 39 | /// 40 | public IEnumerable AllValues => _mLazyFreeSqlQueryMembers.Value; 41 | } 42 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.DosOrm/DotNetCore/Collections/Paginable/Internal/DosQueryState.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Dos.ORM; 4 | using DotNetCore.Collections.Paginable.Abstractions; 5 | 6 | namespace DotNetCore.Collections.Paginable.Internal 7 | { 8 | /// 9 | /// Dos.ORM query state 10 | /// 11 | /// 12 | public class DosQueryState : IQueryEntryState where T : Entity 13 | { 14 | private readonly Lazy> _mLazyDosQueryMembers; 15 | 16 | /// 17 | /// Dos.ORM query state 18 | /// 19 | /// 20 | /// 21 | /// 22 | /// 23 | public DosQueryState(FromSection query, int currentPageNumber, int pageSize, Func, FromSection> additionalQueryFunc = null) 24 | { 25 | if (query is null) 26 | throw new ArgumentNullException(nameof(query)); 27 | 28 | if (currentPageNumber < 0) 29 | throw new ArgumentOutOfRangeException(nameof(currentPageNumber), $"{nameof(currentPageNumber)} can not be less than zero"); 30 | 31 | if (pageSize < 0) 32 | throw new ArgumentOutOfRangeException(nameof(pageSize), $"{nameof(pageSize)} can not be less than zero"); 33 | 34 | _mLazyDosQueryMembers = new Lazy>(() => (additionalQueryFunc?.Invoke(query) ?? query).Page(pageSize, currentPageNumber).ToList()); 35 | } 36 | 37 | /// 38 | /// Get all value. 39 | /// 40 | public IEnumerable AllValues => _mLazyDosQueryMembers.Value; 41 | } 42 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.Chloe/DotNetCore/Collections/Paginable/Internal/ChloeQueryState.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Chloe; 4 | using DotNetCore.Collections.Paginable.Abstractions; 5 | 6 | namespace DotNetCore.Collections.Paginable.Internal 7 | { 8 | /// 9 | /// Chloe query state 10 | /// 11 | /// 12 | public class ChloeQueryState : IQueryEntryState 13 | { 14 | private readonly Lazy> _mLazyChloeQueryMembers; 15 | 16 | /// 17 | /// Chloe query state 18 | /// 19 | /// 20 | /// 21 | /// 22 | /// 23 | public ChloeQueryState(IQuery query, int currentPageNumber, int pageSize, Func, IQuery> additionalQueryFunc = null) 24 | { 25 | if (query is null) 26 | throw new ArgumentNullException(nameof(query)); 27 | 28 | if (currentPageNumber < 0) 29 | throw new ArgumentOutOfRangeException(nameof(currentPageNumber), $"{nameof(currentPageNumber)} can not be less than zero"); 30 | 31 | if (pageSize < 0) 32 | throw new ArgumentOutOfRangeException(nameof(pageSize), $"{nameof(pageSize)} can not be less than zero"); 33 | 34 | InternalChloeQuery = query.TakePage(currentPageNumber, pageSize); 35 | _mLazyChloeQueryMembers = new Lazy>(() => (additionalQueryFunc?.Invoke(InternalChloeQuery) ?? InternalChloeQuery).ToList()); 36 | } 37 | 38 | private IQuery InternalChloeQuery { get; set; } 39 | 40 | /// 41 | /// Get all value. 42 | /// 43 | public IEnumerable AllValues => _mLazyChloeQueryMembers.Value; 44 | } 45 | } -------------------------------------------------------------------------------- /performance/DotNetCore.Collections.Paginable.Benchmarks/PaginableBenchmark.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using BenchmarkDotNet.Attributes; 4 | using ABPaginableCollections = PaginableCollections; 5 | 6 | namespace DotNetCore.Collections.Paginable.Benchmarks { 7 | [MaxColumn, MinColumn] 8 | public class PaginableBenchmark { 9 | private readonly IEnumerable _list; 10 | 11 | public PaginableBenchmark() { 12 | _list = Enumerable.Range(0, 10000000); 13 | } 14 | 15 | [Benchmark] 16 | public int DotNetCoreCollectionEnumerable() { 17 | var paginable = _list.GetPage(15, 50); 18 | return paginable.TotalPageCount; 19 | } 20 | 21 | [Benchmark] 22 | public int PaginableCollectionEnumerable() { 23 | var paginable = ABPaginableCollections.EnumerableExtensions.ToPaginable(_list, 15, 50); 24 | return paginable.Count; 25 | } 26 | 27 | [Benchmark] 28 | public int DotNetCoreCollectionQueryable() { 29 | var paginable = _list.AsQueryable().GetPage(15, 50); 30 | return paginable.TotalPageCount; 31 | } 32 | 33 | [Benchmark] 34 | public int PaginableCollectionQueryable() { 35 | var paginable = ABPaginableCollections.PaginableExtensions.ToPaginable(_list.AsQueryable(), 15, 50); 36 | return paginable.Count; 37 | } 38 | 39 | //[Benchmark] 40 | public int DotNetCoreCollectionEnumerable_ToPaginable() { 41 | var paginable = _list.ToPaginable(50); 42 | var page = paginable.GetPage(15); 43 | return page.TotalPageCount; 44 | } 45 | 46 | //[Benchmark] 47 | public int DotNetCoreCollectionQueryable_ToPaginable() { 48 | var paginable = _list.AsQueryable().ToPaginable(50); 49 | var page = paginable.GetPage(15); 50 | return page.TotalPageCount; 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable/DotNetCore/Collections/Paginable/Internal/PageMemberFactory.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using DotNetCore.Collections.Paginable.Abstractions; 4 | 5 | namespace DotNetCore.Collections.Paginable.Internal 6 | { 7 | /// 8 | /// Page member factory 9 | /// 10 | public static class PageMemberFactory 11 | { 12 | /// 13 | /// Create a new instance of 14 | /// 15 | /// 16 | /// 17 | /// 18 | /// 19 | /// 20 | public static PageMember Create(T memberValue, int offset, ref int startIndex) 21 | => new(memberValue, offset, ref startIndex); 22 | 23 | /// 24 | /// Create a new instance of 25 | /// 26 | /// 27 | /// 28 | /// 29 | /// 30 | /// 31 | /// 32 | public static PageMember Create(IEnumerable memberColl, int index, int offset, ref int startIndex) 33 | => new(memberColl.ElementAt(index), offset, ref startIndex); 34 | 35 | /// 36 | /// Create a new instance of 37 | /// 38 | /// 39 | /// 40 | /// 41 | /// 42 | /// 43 | public static PageMember Create(IQueryEntryState state, int offset, ref int startIndex) 44 | => new(state, offset, ref startIndex); 45 | } 46 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.Chloe/DotNetCore/Collections/Paginable/Internal/PaginableChloeCollFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Chloe; 5 | 6 | namespace DotNetCore.Collections.Paginable.Internal 7 | { 8 | internal static class PaginableChloeCollFactory 9 | { 10 | /// 11 | /// Get real member count
. 12 | /// first parameter(l) means limitedMemberCount
, 13 | /// second parameter(c) means count. 14 | ///
15 | /// 16 | private static Func> GetRealMemberCountFunc() 17 | => l => c => l.IsValid() && l.HasValue ? l.Value > c ? c : l.Value : c; 18 | 19 | /// 20 | /// Get real page count
. 21 | /// first parameter(m) means real member count, which has been gotten from
, 22 | /// second parameter(s) means page size. 23 | ///
24 | /// 25 | private static Func> GetRealPageCountFunc() 26 | => m => s => (int) Math.Ceiling((double) m / (double) s); 27 | 28 | /// 29 | /// Make Chloe.Query`1 source to ChloePage collection. 30 | /// 31 | /// 32 | /// 33 | /// 34 | /// 35 | /// 36 | public static PaginableChloeQuery CreatePageSet(IQuery query, int? pageSize = null, int? limitedMemberCount = null) 37 | { 38 | if (query is null) 39 | throw new ArgumentNullException(nameof(query)); 40 | 41 | pageSize ??= PaginableSettingsManager.Settings.DefaultPageSize; 42 | 43 | var size = pageSize.Value; 44 | var realMemberCount = GetRealMemberCountFunc()(limitedMemberCount)(ChloeHelper.Count(query)); 45 | var realPageCount = GetRealPageCountFunc()(realMemberCount)(size); 46 | 47 | return limitedMemberCount.IsValid() && limitedMemberCount.HasValue 48 | ? new PaginableChloeQuery(query, size, realPageCount, realMemberCount, limitedMemberCount.Value) 49 | : new PaginableChloeQuery(query, size, realPageCount, realMemberCount); 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.NHibernate/DotNetCore/Collections/Paginable/Internal/PaginableNhCoreCollFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NHibernate; 3 | 4 | // ReSharper disable RedundantCast 5 | 6 | namespace DotNetCore.Collections.Paginable.Internal 7 | { 8 | internal static class PaginableNhCoreCollFactory 9 | { 10 | /// 11 | /// Get real member count
. 12 | /// first parameter(l) means limitedMemberCount
, 13 | /// second parameter(c) means count. 14 | ///
15 | /// 16 | private static Func> GetRealMemberCountFunc() 17 | => l => c => l.IsValid() && l.HasValue ? l.Value > c ? c : l.Value : c; 18 | 19 | /// 20 | /// Get real page count
. 21 | /// first parameter(m) means real member count, which has been gotten from
, 22 | /// second parameter(s) means page size. 23 | ///
24 | /// 25 | private static Func> GetRealPageCountFunc() 26 | => m => s => (int) Math.Ceiling((double) m / (double) s); 27 | 28 | /// 29 | /// Make NHibernate QueryOver`1 source to NHibernatePage collection. 30 | /// 31 | /// 32 | /// 33 | /// 34 | /// 35 | /// 36 | public static PaginableNhCoreQuery CreatePageSet(IQueryOver queryOver, int? pageSize = null, int? limitedMemberCount = null) 37 | { 38 | if (queryOver is null) 39 | throw new ArgumentNullException(nameof(queryOver)); 40 | 41 | pageSize ??= PaginableSettingsManager.Settings.DefaultPageSize; 42 | 43 | var size = pageSize.Value; 44 | var realMemberCount = GetRealMemberCountFunc()(limitedMemberCount)(NhQueryOverHelper.Count(queryOver)); 45 | var realPageCount = GetRealPageCountFunc()(realMemberCount)(size); 46 | 47 | return limitedMemberCount.IsValid() && limitedMemberCount.HasValue 48 | ? new PaginableNhCoreQuery(queryOver, size, realPageCount, realMemberCount, limitedMemberCount.Value) 49 | : new PaginableNhCoreQuery(queryOver, size, realPageCount, realMemberCount); 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.SqlSugar/DotNetCore/Collections/Paginable/Internal/PaginableSqlSugarCollFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics.CodeAnalysis; 3 | using SqlSugar; 4 | 5 | namespace DotNetCore.Collections.Paginable.Internal 6 | { 7 | internal static class PaginableSqlSugarCollFactory 8 | { 9 | /// 10 | /// Get real member count
. 11 | /// first parameter(l) means limitedMemberCount
, 12 | /// second parameter(c) means count. 13 | ///
14 | /// 15 | private static Func> GetRealMemberCountFunc() 16 | => l => c => l.IsValid() && l.HasValue ? l.Value > c ? c : l.Value : c; 17 | 18 | /// 19 | /// Get real page count
. 20 | /// first parameter(m) means real member count, which has been gotten from
, 21 | /// second parameter(s) means page size. 22 | ///
23 | /// 24 | [SuppressMessage("ReSharper", "RedundantCast")] 25 | private static Func> GetRealPageCountFunc() 26 | => m => s => (int) Math.Ceiling((double) m / (double) s); 27 | 28 | /// 29 | /// Make SqlSugarQueryable source to SqlSugarPage collection. 30 | /// 31 | /// 32 | /// 33 | /// 34 | /// 35 | /// 36 | public static PaginableSqlSugarQuery CreatePageSet(ISugarQueryable query, int? pageSize = null, int? limitedMemberCount = null) 37 | { 38 | if (query is null) 39 | throw new ArgumentNullException(nameof(query)); 40 | 41 | pageSize ??= PaginableSettingsManager.Settings.DefaultPageSize; 42 | 43 | var size = pageSize.Value; 44 | var realMemberCount = GetRealMemberCountFunc()(limitedMemberCount)(SqlSugarHelper.Count(query)); 45 | var realPageCount = GetRealPageCountFunc()(realMemberCount)(size); 46 | 47 | return limitedMemberCount.IsValid() && limitedMemberCount.HasValue 48 | ? new PaginableSqlSugarQuery(query, size, realPageCount, realMemberCount, limitedMemberCount.Value) 49 | : new PaginableSqlSugarQuery(query, size, realPageCount, realMemberCount); 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /tests/DotNetCore.Collections.Paginable.DbTests/DotNetCore.Collections.Paginable.DbTests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net5.0 4 | false 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | System 31 | 32 | 33 | System.Data 34 | 35 | 36 | System.Xml 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.SqlKata/DotNetCore/Collections/Paginable/Internal/PaginableSqlKataCollFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics.CodeAnalysis; 3 | using SqlKata; 4 | 5 | namespace DotNetCore.Collections.Paginable.Internal 6 | { 7 | internal static class PaginableSqlKataCollFactory 8 | { 9 | /// 10 | /// Get real member count
. 11 | /// first parameter(l) means limitedMemberCount
, 12 | /// second parameter(c) means count. 13 | ///
14 | /// 15 | private static Func> GetRealMemberCountFunc() 16 | => l => c => l.IsValid() && l.HasValue ? l.Value > c ? c : l.Value : c; 17 | 18 | /// 19 | /// Get real page count
. 20 | /// first parameter(m) means real member count, which has been gotten from
, 21 | /// second parameter(s) means page size. 22 | ///
23 | /// 24 | [SuppressMessage("ReSharper", "RedundantCast")] 25 | private static Func> GetRealPageCountFunc() 26 | => m => s => (int) Math.Ceiling((double) m / (double) s); 27 | 28 | /// 29 | /// Make SqlKata.Query source to SqlKataPage collection. 30 | /// 31 | /// element type of your enumerable result 32 | /// SqlKata.Query 33 | /// page size 34 | /// limited member count 35 | /// 36 | public static PaginableSqlKataQuery CreatePageSet(Query query, int? pageSize = null, int? limitedMemberCount = null) 37 | { 38 | if (query is null) 39 | throw new ArgumentNullException(nameof(query)); 40 | 41 | pageSize ??= PaginableSettingsManager.Settings.DefaultPageSize; 42 | 43 | var size = pageSize.Value; 44 | var realMemberCount = GetRealMemberCountFunc()(limitedMemberCount)(SqlKataHelper.Count(query)); 45 | var realPageCount = GetRealPageCountFunc()(realMemberCount)(size); 46 | 47 | return limitedMemberCount.IsValid() && limitedMemberCount.HasValue 48 | ? new PaginableSqlKataQuery(query, size, realPageCount, realMemberCount, limitedMemberCount.Value) 49 | : new PaginableSqlKataQuery(query, size, realPageCount, realMemberCount); 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable/DotNetCore/Collections/Paginable/Extensions/PageExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | // ReSharper disable once CheckNamespace 4 | namespace DotNetCore.Collections.Paginable 5 | { 6 | /// 7 | /// Extensions for page 8 | /// 9 | public static class PageExtensions 10 | { 11 | /// 12 | /// Is current page thr first page? 13 | /// 14 | /// Page 15 | /// 16 | public static bool IsFirst(this IPage page) 17 | { 18 | if (page is null) 19 | throw new ArgumentNullException(nameof(page), $"{nameof(page)} can not be null."); 20 | return !page.HasPrevious; 21 | } 22 | 23 | /// 24 | /// Is current page the last page? 25 | /// 26 | /// Page 27 | /// 28 | public static bool IsLast(this IPage page) 29 | { 30 | if (page is null) 31 | throw new ArgumentNullException(nameof(page), $"{nameof(page)} can not be null."); 32 | return !page.HasNext; 33 | } 34 | 35 | /// 36 | /// The number of the first item of current page. 37 | /// 38 | /// Page 39 | /// 40 | public static int FromMemberNumber(this IPage page) 41 | { 42 | if (page is null) 43 | throw new ArgumentNullException(nameof(page), $"{nameof(page)} can not be null."); 44 | 45 | if (page.TotalMemberCount == 0) 46 | return 0; 47 | 48 | if (!page.HasPrevious) 49 | return 1; 50 | 51 | return (page.CurrentPageNumber - 1) * page.PageSize + 1; 52 | } 53 | 54 | /// 55 | /// The number of the last item of current page. 56 | /// 57 | /// Page 58 | /// 59 | public static int ToMemberNumber(this IPage page) 60 | { 61 | if (page is null) 62 | throw new ArgumentNullException(nameof(page), $"{nameof(page)} can not be null."); 63 | 64 | if (page.TotalMemberCount == 0) 65 | return 0; 66 | 67 | if (!page.HasNext) 68 | return (page.CurrentPageNumber - 1) * page.PageSize + page.CurrentPageSize; 69 | 70 | return page.CurrentPageNumber * page.PageSize; 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /tests/DotNetCore.Collections.Paginable.DbTests/Scripts/TestDataScript.sql: -------------------------------------------------------------------------------- 1 | set IDENTITY_INSERT Int32Samples on 2 | INSERT INTO Int32Samples 3 | (Id) 4 | VALUES 5 | (1), 6 | (2), 7 | (3), 8 | (4), 9 | (5), 10 | (6), 11 | (7), 12 | (8), 13 | (9), 14 | (10), 15 | (11), 16 | (12), 17 | (13), 18 | (14), 19 | (15), 20 | (16), 21 | (17), 22 | (18), 23 | (19), 24 | (20), 25 | (21), 26 | (22), 27 | (23), 28 | (24), 29 | (25), 30 | (26), 31 | (27), 32 | (28), 33 | (29), 34 | (30), 35 | (31), 36 | (32), 37 | (33), 38 | (34), 39 | (35), 40 | (36), 41 | (37), 42 | (38), 43 | (39), 44 | (40), 45 | (41), 46 | (42), 47 | (43), 48 | (44), 49 | (45), 50 | (46), 51 | (47), 52 | (48), 53 | (49), 54 | (50), 55 | (51), 56 | (52), 57 | (53), 58 | (54), 59 | (55), 60 | (56), 61 | (57), 62 | (58), 63 | (59), 64 | (60), 65 | (61), 66 | (62), 67 | (63), 68 | (64), 69 | (65), 70 | (66), 71 | (67), 72 | (68), 73 | (69), 74 | (70), 75 | (71), 76 | (72), 77 | (73), 78 | (74), 79 | (75), 80 | (76), 81 | (77), 82 | (78), 83 | (79), 84 | (80), 85 | (81), 86 | (82), 87 | (83), 88 | (84), 89 | (85), 90 | (86), 91 | (87), 92 | (88), 93 | (89), 94 | (90), 95 | (91), 96 | (92), 97 | (93), 98 | (94), 99 | (95), 100 | (96), 101 | (97), 102 | (98), 103 | (99), 104 | (100), 105 | (101), 106 | (102), 107 | (103), 108 | (104), 109 | (105), 110 | (106), 111 | (107), 112 | (108), 113 | (109), 114 | (110), 115 | (111), 116 | (112), 117 | (113), 118 | (114), 119 | (115), 120 | (116), 121 | (117), 122 | (118), 123 | (119), 124 | (120), 125 | (121), 126 | (122), 127 | (123), 128 | (124), 129 | (125), 130 | (126), 131 | (127), 132 | (128), 133 | (129), 134 | (130), 135 | (131), 136 | (132), 137 | (133), 138 | (134), 139 | (135), 140 | (136), 141 | (137), 142 | (138), 143 | (139), 144 | (140), 145 | (141), 146 | (142), 147 | (143), 148 | (144), 149 | (145), 150 | (146), 151 | (147), 152 | (148), 153 | (149), 154 | (150), 155 | (151), 156 | (152), 157 | (153), 158 | (154), 159 | (155), 160 | (156), 161 | (157), 162 | (158), 163 | (159), 164 | (160), 165 | (161), 166 | (162), 167 | (163), 168 | (164), 169 | (165), 170 | (166), 171 | (167), 172 | (168), 173 | (169), 174 | (170), 175 | (171), 176 | (172), 177 | (173), 178 | (174), 179 | (175), 180 | (176), 181 | (177), 182 | (178), 183 | (179), 184 | (180), 185 | (181), 186 | (182), 187 | (183), 188 | (184), 189 | (185), 190 | (186), 191 | (187), 192 | (188), 193 | (189), 194 | (190), 195 | (191), 196 | (192), 197 | (193), 198 | (194), 199 | (195), 200 | (196), 201 | (197), 202 | (198), 203 | (199), 204 | (200), 205 | (201), 206 | (202), 207 | (203), 208 | (204), 209 | (205), 210 | (206), 211 | (207), 212 | (208), 213 | (209), 214 | (210) -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.DosOrm/DotNetCore/Collections/Paginable/Internal/PaginableDosCollFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics.CodeAnalysis; 3 | using Dos.ORM; 4 | 5 | namespace DotNetCore.Collections.Paginable.Internal 6 | { 7 | internal static class PaginableDosCollFactory 8 | { 9 | /// 10 | /// Get real member count
. 11 | /// first parameter(l) means limitedMemberCount
, 12 | /// second parameter(c) means count. 13 | ///
14 | /// 15 | private static Func> GetRealMemberCountFunc() 16 | => l => c => l.IsValid() && l.HasValue ? l.Value > c ? c : l.Value : c; 17 | 18 | /// 19 | /// Get real page count
. 20 | /// first parameter(m) means real member count, which has been gotten from
, 21 | /// second parameter(s) means page size. 22 | ///
23 | /// 24 | [SuppressMessage("ReSharper", "RedundantCast")] 25 | private static Func> GetRealPageCountFunc() 26 | => m => s => (int) Math.Ceiling((double) m / (double) s); 27 | 28 | /// 29 | /// Make Dos.ORM Query`1 source to DosePage collection. 30 | /// 31 | /// 32 | /// 33 | /// 34 | /// 35 | /// 36 | /// 37 | public static PaginableDosQuery CreatePageSet(FromSection query, int? pageSize = null, int? limitedMemberCount = null, 38 | Func, FromSection> additionalQueryFunc = null) where T : Entity 39 | { 40 | if (query is null) 41 | throw new ArgumentNullException(nameof(query)); 42 | 43 | pageSize ??= PaginableSettingsManager.Settings.DefaultPageSize; 44 | 45 | var size = pageSize.Value; 46 | var realMemberCount = GetRealMemberCountFunc()(limitedMemberCount)(DosHelper.Count(query)); 47 | var realPageCount = GetRealPageCountFunc()(realMemberCount)(size); 48 | 49 | return limitedMemberCount.IsValid() && limitedMemberCount.HasValue 50 | ? new PaginableDosQuery(query, size, realPageCount, realMemberCount, limitedMemberCount.Value, additionalQueryFunc) 51 | : new PaginableDosQuery(query, size, realPageCount, realMemberCount, additionalQueryFunc); 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable/DotNetCore/Collections/Paginable/PageMetadata.cs: -------------------------------------------------------------------------------- 1 | namespace DotNetCore.Collections.Paginable 2 | { 3 | /// 4 | /// Page metadata 5 | /// 6 | public class PageMetadata 7 | { 8 | /// 9 | /// Create a new instance of . 10 | /// 11 | /// 12 | public PageMetadata(IPage page) 13 | { 14 | TotalPageCount = page.TotalPageCount; 15 | RealPageCount = page.TotalMemberCount == 0 ? 0 : page.TotalPageCount; 16 | TotalMemberCount = page.TotalMemberCount; 17 | PageSize = page.PageSize; 18 | 19 | CurrentPageNumber = page.CurrentPageNumber; 20 | CurrentPageSize = page.CurrentPageSize; 21 | 22 | HasPrevious = page.HasPrevious; 23 | HasNext = page.HasNext; 24 | } 25 | 26 | /// 27 | /// Gets total page count 28 | /// 29 | public int TotalPageCount { get; } 30 | 31 | /// 32 | /// Gets real page count 33 | /// 34 | public int RealPageCount { get; } 35 | 36 | /// 37 | /// Gets total member count 38 | /// 39 | public int TotalMemberCount { get; } 40 | 41 | /// 42 | /// Gets current page number 43 | /// 44 | public int CurrentPageNumber { get; } 45 | 46 | /// 47 | /// Gets page size 48 | /// 49 | public int PageSize { get; } 50 | 51 | /// 52 | /// Gets current page size 53 | /// 54 | public int CurrentPageSize { get; } 55 | 56 | /// 57 | /// Has previous. If this page is the first page, then returns false. 58 | /// 59 | public bool HasPrevious { get; } 60 | 61 | /// 62 | /// Has next. If this page is the last page, then returns false. 63 | /// 64 | public bool HasNext { get; } 65 | 66 | /// 67 | public override string ToString() 68 | { 69 | return $@" 70 | =====SUMMARY===== 71 | TotalPageCount = {TotalPageCount} 72 | RealPageCount = {RealPageCount} 73 | TotalMemberCount = {TotalMemberCount} 74 | PageSize = {PageSize} 75 | 76 | =====CURRENT===== 77 | CurrentPageNumber = {CurrentPageNumber} 78 | CurrentPageSize = {CurrentPageSize} 79 | 80 | =====NAVIGATOR===== 81 | HasPrevious = {(HasPrevious ? "Yes" : "No")} 82 | HasNext = {(HasNext ? "Yes" : "No")} 83 | "; 84 | } 85 | } 86 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.FreeSql/DotNetCore/Collections/Paginable/Internal/PaginableFreeSqlCollFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics.CodeAnalysis; 3 | using System.Runtime.CompilerServices; 4 | using FreeSql; 5 | 6 | namespace DotNetCore.Collections.Paginable.Internal 7 | { 8 | internal static class PaginableFreeSqlCollFactory 9 | { 10 | /// 11 | /// Get real member count
. 12 | /// first parameter(l) means limitedMemberCount
, 13 | /// second parameter(c) means count. 14 | ///
15 | /// 16 | private static Func> GetRealMemberCountFunc() 17 | => l => c => l.IsValid() && l.HasValue ? l.Value > c ? c : l.Value : c; 18 | 19 | /// 20 | /// Get real page count
. 21 | /// first parameter(m) means real member count, which has been gotten from
, 22 | /// second parameter(s) means page size. 23 | ///
24 | /// 25 | [SuppressMessage("ReSharper", "RedundantCast")] 26 | private static Func> GetRealPageCountFunc() 27 | => m => s => (int) Math.Ceiling((double) m / (double) s); 28 | 29 | /// 30 | /// Make FreeSql.Select`1 source to FreeSqlPage collection. 31 | /// 32 | /// 33 | /// 34 | /// 35 | /// 36 | /// 37 | /// 38 | public static PaginableFreeSqlQuery CreatePageSet(ISelect select, int? pageSize = null, int? limitedMemberCount = null, bool? includeNestedMembers = null) 39 | where T : class 40 | { 41 | if (select is null) 42 | throw new ArgumentNullException(nameof(select)); 43 | 44 | pageSize ??= PaginableSettingsManager.Settings.DefaultPageSize; 45 | includeNestedMembers ??= false; 46 | 47 | var size = pageSize.Value; 48 | var realMemberCount = GetRealMemberCountFunc()(limitedMemberCount)(FreeSqlHelper.Count(select).AsInt32()); 49 | var realPageCount = GetRealPageCountFunc()(realMemberCount)(size); 50 | 51 | return limitedMemberCount.IsValid() && limitedMemberCount.HasValue 52 | ? new PaginableFreeSqlQuery(select, size, realPageCount, realMemberCount, limitedMemberCount.Value, includeNestedMembers.Value) 53 | : new PaginableFreeSqlQuery(select, size, realPageCount, realMemberCount, includeNestedMembers.Value); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /tests/DotNetCore.Collections.Paginable.DbTests/SqlSugarTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using DotNetCore.Collections.Paginable.DbTests.Models; 5 | using Shouldly; 6 | using SqlSugar; 7 | using Xunit; 8 | 9 | namespace DotNetCore.Collections.Paginable.DbTests 10 | { 11 | public class SqlSugarTests 12 | { 13 | private readonly string connectionString = @"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=D:\Development\Collections\tests\DotNetCore.Collections.Paginable.DbTests\DataSource\Samples.mdf;Integrated Security=True"; 14 | 15 | private readonly SqlSugarClient _sqlSugar; 16 | 17 | public SqlSugarTests() 18 | { 19 | _sqlSugar = new SqlSugarClient(new ConnectionConfig 20 | { 21 | ConnectionString = connectionString, 22 | DbType = DbType.SqlServer, 23 | IsAutoCloseConnection = true 24 | }); 25 | 26 | _sqlSugar.MappingTables.Add("Int32Sample", "Int32Samples"); 27 | } 28 | 29 | [Fact] 30 | public void GetPageTest() 31 | { 32 | var page = _sqlSugar.Queryable().GetPage(1, 9); 33 | page.TotalPageCount.ShouldBe(24); 34 | page.TotalMemberCount.ShouldBe(210); 35 | page.CurrentPageNumber.ShouldBe(1); 36 | page.PageSize.ShouldBe(9); 37 | page.CurrentPageSize.ShouldBe(9); 38 | page.HasNext.ShouldBeTrue(); 39 | page.HasPrevious.ShouldBeFalse(); 40 | 41 | page[0].Value.Id.ShouldBe(1); 42 | page[1].Value.Id.ShouldBe(2); 43 | page[2].Value.Id.ShouldBe(3); 44 | page[3].Value.Id.ShouldBe(4); 45 | page[4].Value.Id.ShouldBe(5); 46 | page[5].Value.Id.ShouldBe(6); 47 | page[6].Value.Id.ShouldBe(7); 48 | page[7].Value.Id.ShouldBe(8); 49 | page[8].Value.Id.ShouldBe(9); 50 | } 51 | 52 | [Fact] 53 | public void ToPaginableTest() 54 | { 55 | var list = _sqlSugar.Queryable().ToPaginable(9); 56 | var page = list.GetPage(2); 57 | page.TotalPageCount.ShouldBe(24); 58 | page.TotalMemberCount.ShouldBe(210); 59 | page.CurrentPageNumber.ShouldBe(2); 60 | page.PageSize.ShouldBe(9); 61 | page.CurrentPageSize.ShouldBe(9); 62 | page.HasNext.ShouldBeTrue(); 63 | page.HasPrevious.ShouldBeTrue(); 64 | 65 | page[0].Value.Id.ShouldBe(10); 66 | page[1].Value.Id.ShouldBe(11); 67 | page[2].Value.Id.ShouldBe(12); 68 | page[3].Value.Id.ShouldBe(13); 69 | page[4].Value.Id.ShouldBe(14); 70 | page[5].Value.Id.ShouldBe(15); 71 | page[6].Value.Id.ShouldBe(16); 72 | page[7].Value.Id.ShouldBe(17); 73 | page[8].Value.Id.ShouldBe(18); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.SqlKata/DotNetCore/Collections/Paginable/SqlKataPage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using DotNetCore.Collections.Paginable.Internal; 4 | using SqlKata; 5 | 6 | // ReSharper disable RedundantBaseQualifier 7 | // ReSharper disable RedundantCast 8 | 9 | namespace DotNetCore.Collections.Paginable 10 | { 11 | /// 12 | /// SqlKata page 13 | /// 14 | /// 15 | public class SqlKataPage : PageBase 16 | { 17 | /// 18 | /// SqlKata page 19 | /// 20 | /// 21 | /// 22 | /// 23 | /// 24 | // ReSharper disable once RedundantBaseConstructorCall 25 | public SqlKataPage(Query query, int currentPageNumber, int pageSize, int totalMemberCount) : base(false) 26 | { 27 | var skip = (currentPageNumber - 1) * pageSize; 28 | var state = new SqlKataQueryState(query.Clone(), currentPageNumber, pageSize); 29 | InitializeMetaInfo()(currentPageNumber)(pageSize)(totalMemberCount)(skip)(); 30 | base._initializeAction = InitializeMemberList()(state)(CurrentPageSize)(skip); 31 | } 32 | 33 | /// 34 | /// Get empty page 35 | /// 36 | /// 37 | public static EmptyPage Empty() => new(); 38 | 39 | private Func>>> InitializeMetaInfo() => c => s => t => k => () => 40 | { 41 | // c = current page number 42 | // s = page size 43 | // t = total member count 44 | // k = skip 45 | var totalPageCount = (int) Math.Ceiling((double) t / (double) s); 46 | totalPageCount = totalPageCount < 0 ? 0 : totalPageCount; 47 | base.TotalPageCount = totalPageCount == 0 ? 1 : totalPageCount; 48 | base.TotalMemberCount = t; 49 | base.CurrentPageNumber = c; 50 | base.PageSize = s; 51 | base.CurrentPageSize = c == totalPageCount 52 | ? k == 0 53 | ? t 54 | : t % k 55 | : totalPageCount == 0 56 | ? 0 57 | : s; 58 | 59 | base.HasPrevious = c > 1; 60 | base.HasNext = c < base.TotalPageCount; 61 | }; 62 | 63 | private Func, Func>> InitializeMemberList() => state => s => k => () => 64 | { 65 | // s = page size 66 | // k = skip 67 | base._memberList = new List>(s); 68 | for (var i = 0; i < s; i++) 69 | { 70 | base._memberList.Add(PageMemberFactory.Create(state, i, ref k)); 71 | } 72 | }; 73 | } 74 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.NHibernate/DotNetCore/Collections/Paginable/NhCorePage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using DotNetCore.Collections.Paginable.Internal; 4 | using NHibernate; 5 | 6 | // ReSharper disable RedundantCast 7 | // ReSharper disable RedundantBaseQualifier 8 | 9 | namespace DotNetCore.Collections.Paginable 10 | { 11 | /// 12 | /// NHibernate page 13 | /// 14 | /// 15 | public class NhCorePage : PageBase 16 | { 17 | /// 18 | /// NHibernate page 19 | /// 20 | /// 21 | /// 22 | /// 23 | /// 24 | // ReSharper disable once RedundantBaseConstructorCall 25 | public NhCorePage(IQueryOver queryOver, int currentPageNumber, int pageSize, int totalMemberCount) : base(false) 26 | { 27 | var skip = (currentPageNumber - 1) * pageSize; 28 | var state = new NhCoreQueryState(queryOver, skip, pageSize); 29 | InitializeMetaInfo()(currentPageNumber)(pageSize)(totalMemberCount)(skip)(); 30 | base._initializeAction = InitializeMemberList()(state)(CurrentPageSize)(skip); 31 | } 32 | 33 | /// 34 | /// Get empty page 35 | /// 36 | /// 37 | public static EmptyPage Empty() => new(); 38 | 39 | private Func>>> InitializeMetaInfo() => c => s => t => k => () => 40 | { 41 | // c = current page number 42 | // s = page size 43 | // t = total member count 44 | // k = skip 45 | var totalPageCount = (int) Math.Ceiling((double) t / (double) s); 46 | totalPageCount = totalPageCount < 0 ? 0 : totalPageCount; 47 | base.TotalPageCount = totalPageCount == 0 ? 1 : totalPageCount; 48 | base.TotalMemberCount = t; 49 | base.CurrentPageNumber = c; 50 | base.PageSize = s; 51 | base.CurrentPageSize = c == totalPageCount 52 | ? k == 0 53 | ? t 54 | : t % k 55 | : totalPageCount == 0 56 | ? 0 57 | : s; 58 | 59 | base.HasPrevious = c > 1; 60 | base.HasNext = c < base.TotalPageCount; 61 | }; 62 | 63 | private Func, Func>> InitializeMemberList() => state => s => k => () => 64 | { 65 | // s = page size 66 | // k = skip 67 | base._memberList = new List>(s); 68 | for (var i = 0; i < s; i++) 69 | { 70 | base._memberList.Add(PageMemberFactory.Create(state, i, ref k)); 71 | } 72 | }; 73 | } 74 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.SqlSugar/DotNetCore/Collections/Paginable/SqlSugarPage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using DotNetCore.Collections.Paginable.Internal; 4 | using SqlSugar; 5 | 6 | // ReSharper disable RedundantBaseQualifier 7 | // ReSharper disable RedundantCast 8 | 9 | namespace DotNetCore.Collections.Paginable 10 | { 11 | /// 12 | /// SqlSugar page 13 | /// 14 | /// 15 | public class SqlSugarPage : PageBase 16 | { 17 | /// 18 | /// SqlSugar page 19 | /// 20 | /// 21 | /// 22 | /// 23 | /// 24 | // ReSharper disable once RedundantBaseConstructorCall 25 | public SqlSugarPage(ISugarQueryable query, int currentPageNumber, int pageSize, int totalMemberCount) : base(false) 26 | { 27 | var skip = (currentPageNumber - 1) * pageSize; 28 | var state = new SqlSugarQueryState(query, currentPageNumber, pageSize); 29 | InitializeMetaInfo()(currentPageNumber)(pageSize)(totalMemberCount)(skip)(); 30 | base._initializeAction = InitializeMemberList()(state)(CurrentPageSize)(skip); 31 | } 32 | 33 | /// 34 | /// Get empty page 35 | /// 36 | /// 37 | public static EmptyPage Empty() => new(); 38 | 39 | private Func>>> InitializeMetaInfo() => c => s => t => k => () => 40 | { 41 | // c = current page number 42 | // s = page size 43 | // t = total member count 44 | // k = skip 45 | var totalPageCount = (int) Math.Ceiling((double) t / (double) s); 46 | totalPageCount = totalPageCount < 0 ? 0 : totalPageCount; 47 | base.TotalPageCount = totalPageCount == 0 ? 1 : totalPageCount; 48 | base.TotalMemberCount = t; 49 | base.CurrentPageNumber = c; 50 | base.PageSize = s; 51 | base.CurrentPageSize = c == totalPageCount 52 | ? k == 0 53 | ? t 54 | : t % k 55 | : totalPageCount == 0 56 | ? 0 57 | : s; 58 | 59 | base.HasPrevious = c > 1; 60 | base.HasNext = c < base.TotalPageCount; 61 | }; 62 | 63 | private Func, Func>> InitializeMemberList() => state => s => k => () => 64 | { 65 | // s = page size 66 | // k = skip 67 | base._memberList = new List>(s); 68 | for (var i = 0; i < s; i++) 69 | { 70 | base._memberList.Add(PageMemberFactory.Create(state, i, ref k)); 71 | } 72 | }; 73 | } 74 | } -------------------------------------------------------------------------------- /tests/DotNetCore.Collections.Paginable.DbTests/DosORMTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Dos.ORM; 5 | using DotNetCore.Collections.Paginable.DbTests.Models; 6 | using Shouldly; 7 | using Xunit; 8 | 9 | namespace DotNetCore.Collections.Paginable.DbTests 10 | { 11 | public class DosORMTests 12 | { 13 | private readonly string connectionString = @"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=D:\Development\Collections\tests\DotNetCore.Collections.Paginable.DbTests\DataSource\Samples.mdf;Integrated Security=True"; 14 | 15 | private readonly DbSession _dosOrmSession; 16 | 17 | public DosORMTests() 18 | { 19 | _dosOrmSession = new DbSession(DatabaseType.SqlServer, connectionString); 20 | } 21 | 22 | [Fact] 23 | public void GetPageTest() 24 | { 25 | var page = _dosOrmSession.From().GetPage(1, 9); 26 | page.TotalPageCount.ShouldBe(24); 27 | page.TotalMemberCount.ShouldBe(210); 28 | page.CurrentPageNumber.ShouldBe(1); 29 | page.PageSize.ShouldBe(9); 30 | page.CurrentPageSize.ShouldBe(9); 31 | page.HasNext.ShouldBeTrue(); 32 | page.HasPrevious.ShouldBeFalse(); 33 | 34 | page[0].Value.Id.ShouldBe(1); 35 | page[1].Value.Id.ShouldBe(2); 36 | page[2].Value.Id.ShouldBe(3); 37 | page[3].Value.Id.ShouldBe(4); 38 | page[4].Value.Id.ShouldBe(5); 39 | page[5].Value.Id.ShouldBe(6); 40 | page[6].Value.Id.ShouldBe(7); 41 | page[7].Value.Id.ShouldBe(8); 42 | page[8].Value.Id.ShouldBe(9); 43 | } 44 | 45 | [Fact] 46 | public void ToPaginableTest() 47 | { 48 | var list = _dosOrmSession.From().ToPaginable(9); 49 | var page = list.GetPage(2); 50 | page.TotalPageCount.ShouldBe(24); 51 | page.TotalMemberCount.ShouldBe(210); 52 | page.CurrentPageNumber.ShouldBe(2); 53 | page.PageSize.ShouldBe(9); 54 | page.CurrentPageSize.ShouldBe(9); 55 | page.HasNext.ShouldBeTrue(); 56 | page.HasPrevious.ShouldBeTrue(); 57 | 58 | page[0].Value.Id.ShouldBe(10); 59 | page[1].Value.Id.ShouldBe(11); 60 | page[2].Value.Id.ShouldBe(12); 61 | page[3].Value.Id.ShouldBe(13); 62 | page[4].Value.Id.ShouldBe(14); 63 | page[5].Value.Id.ShouldBe(15); 64 | page[6].Value.Id.ShouldBe(16); 65 | page[7].Value.Id.ShouldBe(17); 66 | page[8].Value.Id.ShouldBe(18); 67 | 68 | } 69 | } 70 | 71 | 72 | public class Int32Sample4DosORM : Entity 73 | { 74 | public Int32Sample4DosORM() : base("Int32Samples") { } 75 | 76 | public virtual int Id { get; set; } 77 | 78 | public override Field[] GetPrimaryKeyFields() => new Field[] { new Field("Id"), }; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable/DotNetCore/Collections/Paginable/PageBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | 6 | namespace DotNetCore.Collections.Paginable 7 | { 8 | /// 9 | /// Abstract page base 10 | /// 11 | /// 12 | public abstract class PageBase : IPage 13 | { 14 | /// 15 | /// Member list 16 | /// 17 | // ReSharper disable once InconsistentNaming 18 | protected IList> _memberList; 19 | 20 | /// 21 | /// Initialize action 22 | /// 23 | // ReSharper disable once InconsistentNaming 24 | protected Action _initializeAction; 25 | 26 | private bool _mHasInitialized; 27 | 28 | /// 29 | /// Page base 30 | /// 31 | /// 32 | protected PageBase(bool sourceIsFull) => SourceIsFull = sourceIsFull; 33 | 34 | /// 35 | public IEnumerator> GetEnumerator() 36 | { 37 | CheckOrInitializePage(); 38 | return _memberList.GetEnumerator(); 39 | } 40 | 41 | IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); 42 | 43 | /// 44 | /// Offset mode 45 | /// 46 | protected bool SourceIsFull { get; private set; } 47 | 48 | /// 49 | public int TotalPageCount { get; protected set; } 50 | 51 | /// 52 | public int TotalMemberCount { get; protected set; } 53 | 54 | /// 55 | public int CurrentPageNumber { get; protected set; } 56 | 57 | /// 58 | public int PageSize { get; protected set; } 59 | 60 | /// 61 | public int CurrentPageSize { get; protected set; } 62 | 63 | /// 64 | public bool HasPrevious { get; protected set; } 65 | 66 | /// 67 | public bool HasNext { get; protected set; } 68 | 69 | /// 70 | public IPageMember this[int index] 71 | { 72 | get 73 | { 74 | CheckOrInitializePage(); 75 | return _memberList[index]; 76 | } 77 | } 78 | 79 | /// 80 | public PageMetadata GetMetadata() => new(this); 81 | 82 | /// 83 | public IEnumerable ToOriginalItems() 84 | { 85 | CheckOrInitializePage(); 86 | return _memberList.Select(x => x.Value); 87 | } 88 | 89 | private void CheckOrInitializePage() 90 | { 91 | if (!_mHasInitialized) 92 | { 93 | _initializeAction?.Invoke(); 94 | _mHasInitialized = true; 95 | } 96 | } 97 | } 98 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.Chloe/DotNetCore/Collections/Paginable/ChloePage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Chloe; 4 | using DotNetCore.Collections.Paginable.Internal; 5 | 6 | // ReSharper disable RedundantBaseQualifier 7 | // ReSharper disable RedundantCast 8 | 9 | namespace DotNetCore.Collections.Paginable 10 | { 11 | /// 12 | /// Chloe page 13 | /// 14 | /// 15 | public class ChloePage : PageBase 16 | { 17 | /// 18 | /// Chloe page 19 | /// 20 | /// 21 | /// 22 | /// 23 | /// 24 | /// 25 | // ReSharper disable once RedundantBaseConstructorCall 26 | public ChloePage(IQuery query, int currentPageNumber, int pageSize, int totalMemberCount, Func, IQuery> additionalQueryFunc = null) : base(false) 27 | { 28 | var skip = (currentPageNumber - 1) * pageSize; 29 | var state = new ChloeQueryState(query, currentPageNumber, pageSize, additionalQueryFunc); 30 | InitializeMetaInfo()(currentPageNumber)(pageSize)(totalMemberCount)(skip)(); 31 | base._initializeAction = InitializeMemberList()(state)(CurrentPageSize)(skip); 32 | } 33 | 34 | /// 35 | /// Get empty page 36 | /// 37 | /// 38 | public static EmptyPage Empty() => new(); 39 | 40 | private Func>>> InitializeMetaInfo() => c => s => t => k => () => 41 | { 42 | // c = current page number 43 | // s = page size 44 | // t = total member count 45 | // k = skip 46 | var totalPageCount = (int) Math.Ceiling((double) t / (double) s); 47 | totalPageCount = totalPageCount < 0 ? 0 : totalPageCount; 48 | base.TotalPageCount = totalPageCount == 0 ? 1 : totalPageCount; 49 | base.TotalMemberCount = t; 50 | base.CurrentPageNumber = c; 51 | base.PageSize = s; 52 | base.CurrentPageSize = c == totalPageCount 53 | ? k == 0 54 | ? t 55 | : t % k 56 | : totalPageCount == 0 57 | ? 0 58 | : s; 59 | 60 | base.HasPrevious = c > 1; 61 | base.HasNext = c < base.TotalPageCount; 62 | }; 63 | 64 | private Func, Func>> InitializeMemberList() => state => s => k => () => 65 | { 66 | // s = page size 67 | // k = skip 68 | base._memberList = new List>(s); 69 | for (var i = 0; i < s; i++) 70 | { 71 | base._memberList.Add(PageMemberFactory.Create(state, i, ref k)); 72 | } 73 | }; 74 | } 75 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.FreeSql/DotNetCore/Collections/Paginable/FreeSqlPage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using DotNetCore.Collections.Paginable.Internal; 4 | using FreeSql; 5 | 6 | // ReSharper disable RedundantBaseQualifier 7 | // ReSharper disable RedundantCast 8 | 9 | namespace DotNetCore.Collections.Paginable 10 | { 11 | /// 12 | /// FreeSql page 13 | /// 14 | /// 15 | public class FreeSqlPage : PageBase where T : class 16 | { 17 | /// 18 | /// FreeSql page 19 | /// 20 | /// 21 | /// 22 | /// 23 | /// 24 | /// 25 | // ReSharper disable once RedundantBaseConstructorCall 26 | public FreeSqlPage(ISelect select, int currentPageNumber, int pageSize, int totalMemberCount, bool includeNestedMembers) : base(false) 27 | { 28 | var skip = (currentPageNumber - 1) * pageSize; 29 | var state = new FreeSqlQueryState(select, currentPageNumber, pageSize, includeNestedMembers); 30 | InitializeMetaInfo()(currentPageNumber)(pageSize)(totalMemberCount)(skip)(); 31 | base._initializeAction = InitializeMemberList()(state)(CurrentPageSize)(skip); 32 | } 33 | 34 | /// 35 | /// Get empty page 36 | /// 37 | /// 38 | public static EmptyPage Empty() => new(); 39 | 40 | private Func>>> InitializeMetaInfo() => c => s => t => k => () => 41 | { 42 | // c = current page number 43 | // s = page size 44 | // t = total member count 45 | // k = skip 46 | var totalPageCount = (int) Math.Ceiling((double) t / (double) s); 47 | totalPageCount = totalPageCount < 0 ? 0 : totalPageCount; 48 | base.TotalPageCount = totalPageCount == 0 ? 1 : totalPageCount; 49 | base.TotalMemberCount = t; 50 | base.CurrentPageNumber = c; 51 | base.PageSize = s; 52 | base.CurrentPageSize = c == totalPageCount 53 | ? k == 0 54 | ? t 55 | : t % k 56 | : totalPageCount == 0 57 | ? 0 58 | : s; 59 | 60 | base.HasPrevious = c > 1; 61 | base.HasNext = c < base.TotalPageCount; 62 | }; 63 | 64 | private Func, Func>> InitializeMemberList() => state => s => k => () => 65 | { 66 | // s = page size 67 | // k = skip 68 | base._memberList = new List>(s); 69 | for (var i = 0; i < s; i++) 70 | { 71 | base._memberList.Add(PageMemberFactory.Create(state, i, ref k)); 72 | } 73 | }; 74 | } 75 | } -------------------------------------------------------------------------------- /tests/DotNetCore.Collections.Paginable.DbTests/ChloeTests.cs: -------------------------------------------------------------------------------- 1 | using Chloe.Entity; 2 | using Chloe.Infrastructure; 3 | using Chloe.SqlServer; 4 | using DotNetCore.Collections.Paginable.DbTests.Models; 5 | using Shouldly; 6 | using Xunit; 7 | 8 | namespace DotNetCore.Collections.Paginable.DbTests 9 | { 10 | public class ChloeTests 11 | { 12 | private readonly string connectionString = @"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=D:\Development\Collections\tests\DotNetCore.Collections.Paginable.DbTests\DataSource\Samples.mdf;Integrated Security=True"; 13 | 14 | public ChloeTests() 15 | { 16 | DbConfiguration.UseTypeBuilders(typeof(Int32SampleMap)); 17 | } 18 | 19 | [Fact] 20 | public void GetPageTest() 21 | { 22 | using (var db = new MsSqlContext(connectionString)) 23 | { 24 | var page = db.Query().GetPage(1, 9); 25 | page.TotalPageCount.ShouldBe(24); 26 | page.TotalMemberCount.ShouldBe(210); 27 | page.CurrentPageNumber.ShouldBe(1); 28 | page.PageSize.ShouldBe(9); 29 | page.CurrentPageSize.ShouldBe(9); 30 | page.HasNext.ShouldBeTrue(); 31 | page.HasPrevious.ShouldBeFalse(); 32 | 33 | page[0].Value.Id.ShouldBe(1); 34 | page[1].Value.Id.ShouldBe(2); 35 | page[2].Value.Id.ShouldBe(3); 36 | page[3].Value.Id.ShouldBe(4); 37 | page[4].Value.Id.ShouldBe(5); 38 | page[5].Value.Id.ShouldBe(6); 39 | page[6].Value.Id.ShouldBe(7); 40 | page[7].Value.Id.ShouldBe(8); 41 | page[8].Value.Id.ShouldBe(9); 42 | } 43 | } 44 | 45 | [Fact] 46 | public void ToPaginableTest() 47 | { 48 | using (var db = new MsSqlContext(connectionString)) 49 | { 50 | var list = db.Query().ToPaginable(9); 51 | var page = list.GetPage(2); 52 | page.TotalPageCount.ShouldBe(24); 53 | page.TotalMemberCount.ShouldBe(210); 54 | page.CurrentPageNumber.ShouldBe(2); 55 | page.PageSize.ShouldBe(9); 56 | page.CurrentPageSize.ShouldBe(9); 57 | page.HasNext.ShouldBeTrue(); 58 | page.HasPrevious.ShouldBeTrue(); 59 | 60 | page[0].Value.Id.ShouldBe(10); 61 | page[1].Value.Id.ShouldBe(11); 62 | page[2].Value.Id.ShouldBe(12); 63 | page[3].Value.Id.ShouldBe(13); 64 | page[4].Value.Id.ShouldBe(14); 65 | page[5].Value.Id.ShouldBe(15); 66 | page[6].Value.Id.ShouldBe(16); 67 | page[7].Value.Id.ShouldBe(17); 68 | page[8].Value.Id.ShouldBe(18); 69 | } 70 | } 71 | } 72 | 73 | public class Int32SampleMap : EntityTypeBuilder 74 | { 75 | public Int32SampleMap() 76 | { 77 | this.MapTo("Int32Samples"); 78 | } 79 | } 80 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.DosOrm/DotNetCore/Collections/Paginable/DosPage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Dos.ORM; 4 | using DotNetCore.Collections.Paginable.Internal; 5 | 6 | // ReSharper disable RedundantBaseQualifier 7 | // ReSharper disable RedundantCast 8 | 9 | namespace DotNetCore.Collections.Paginable 10 | { 11 | /// 12 | /// Dos.ORM page 13 | /// 14 | /// 15 | public class DosPage : PageBase where T : Entity 16 | { 17 | /// 18 | /// Dos.ORM page 19 | /// 20 | /// 21 | /// 22 | /// 23 | /// 24 | /// 25 | // ReSharper disable once RedundantBaseConstructorCall 26 | public DosPage(FromSection query, int currentPageNumber, int pageSize, int totalMemberCount, Func, FromSection> additionalQueryFunc = null) : base(false) 27 | { 28 | var skip = (currentPageNumber - 1) * pageSize; 29 | var state = new DosQueryState(query, currentPageNumber, pageSize, additionalQueryFunc); 30 | InitializeMetaInfo()(currentPageNumber)(pageSize)(totalMemberCount)(skip)(); 31 | base._initializeAction = InitializeMemberList()(state)(CurrentPageSize)(skip); 32 | } 33 | 34 | /// 35 | /// Get empty page 36 | /// 37 | /// 38 | public static EmptyPage Empty() => new(); 39 | 40 | private Func>>> InitializeMetaInfo() => c => s => t => k => () => 41 | { 42 | // c = current page number 43 | // s = page size 44 | // t = total member count 45 | // k = skip 46 | var totalPageCount = (int) Math.Ceiling((double) t / (double) s); 47 | totalPageCount = totalPageCount < 0 ? 0 : totalPageCount; 48 | base.TotalPageCount = totalPageCount == 0 ? 1 : totalPageCount; 49 | base.TotalMemberCount = t; 50 | base.CurrentPageNumber = c; 51 | base.PageSize = s; 52 | base.CurrentPageSize = c == totalPageCount 53 | ? k == 0 54 | ? t 55 | : t % k 56 | : totalPageCount == 0 57 | ? 0 58 | : s; 59 | 60 | base.HasPrevious = c > 1; 61 | base.HasNext = c < base.TotalPageCount; 62 | }; 63 | 64 | private Func, Func>> InitializeMemberList() => state => s => k => () => 65 | { 66 | // s = page size 67 | // k = skip 68 | base._memberList = new List>(s); 69 | for (var i = 0; i < s; i++) 70 | { 71 | base._memberList.Add(PageMemberFactory.Create(state, i, ref k)); 72 | } 73 | }; 74 | } 75 | } -------------------------------------------------------------------------------- /tests/DotNetCore.Collections.Paginable.DbTests/SqlKataTests.cs: -------------------------------------------------------------------------------- 1 | using System.Data; 2 | using System.Data.SqlClient; 3 | using DotNetCore.Collections.Paginable.DbTests.Models; 4 | using Shouldly; 5 | using SqlKata.Compilers; 6 | using SqlKata.Execution; 7 | using Xunit; 8 | 9 | namespace DotNetCore.Collections.Paginable.DbTests 10 | { 11 | public class SqlKataTests 12 | { 13 | private readonly string connectionString = @"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=D:\Development\Collections\tests\DotNetCore.Collections.Paginable.DbTests\DataSource\Samples.mdf;Integrated Security=True"; 14 | 15 | [Fact] 16 | public void GetPageTest() 17 | { 18 | using (IDbConnection connection = new SqlConnection(connectionString)) 19 | { 20 | connection.Open(); 21 | 22 | var compiler = new SqlServerCompiler(); 23 | var db = new QueryFactory(connection, compiler); 24 | 25 | var page = db.Query("Int32Samples").GetPage(1, 9); 26 | page.TotalPageCount.ShouldBe(24); 27 | page.TotalMemberCount.ShouldBe(210); 28 | page.CurrentPageNumber.ShouldBe(1); 29 | page.PageSize.ShouldBe(9); 30 | page.CurrentPageSize.ShouldBe(9); 31 | page.HasNext.ShouldBeTrue(); 32 | page.HasPrevious.ShouldBeFalse(); 33 | 34 | page[0].Value.Id.ShouldBe(1); 35 | page[1].Value.Id.ShouldBe(2); 36 | page[2].Value.Id.ShouldBe(3); 37 | page[3].Value.Id.ShouldBe(4); 38 | page[4].Value.Id.ShouldBe(5); 39 | page[5].Value.Id.ShouldBe(6); 40 | page[6].Value.Id.ShouldBe(7); 41 | page[7].Value.Id.ShouldBe(8); 42 | page[8].Value.Id.ShouldBe(9); 43 | 44 | connection.Close(); 45 | } 46 | } 47 | 48 | [Fact] 49 | public void ToPaginableTest() 50 | { 51 | using (IDbConnection connection = new SqlConnection(connectionString)) 52 | { 53 | connection.Open(); 54 | 55 | var compiler = new SqlServerCompiler(); 56 | var db = new QueryFactory(connection, compiler); 57 | 58 | var list = db.Query("Int32Samples").ToPaginable(9); 59 | var page = list.GetPage(2); 60 | page.TotalPageCount.ShouldBe(24); 61 | page.TotalMemberCount.ShouldBe(210); 62 | page.CurrentPageNumber.ShouldBe(2); 63 | page.PageSize.ShouldBe(9); 64 | page.CurrentPageSize.ShouldBe(9); 65 | page.HasNext.ShouldBeTrue(); 66 | page.HasPrevious.ShouldBeTrue(); 67 | 68 | page[0].Value.Id.ShouldBe(10); 69 | page[1].Value.Id.ShouldBe(11); 70 | page[2].Value.Id.ShouldBe(12); 71 | page[3].Value.Id.ShouldBe(13); 72 | page[4].Value.Id.ShouldBe(14); 73 | page[5].Value.Id.ShouldBe(15); 74 | page[6].Value.Id.ShouldBe(16); 75 | page[7].Value.Id.ShouldBe(17); 76 | page[8].Value.Id.ShouldBe(18); 77 | 78 | connection.Close(); 79 | } 80 | } 81 | } 82 | 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable/DotNetCore/Collections/Paginable/QueryablePage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using DotNetCore.Collections.Paginable.Internal; 5 | 6 | // ReSharper disable RedundantBaseQualifier 7 | 8 | namespace DotNetCore.Collections.Paginable 9 | { 10 | /// 11 | /// Queryable page 12 | /// 13 | /// 14 | public class QueryablePage : PageBase 15 | { 16 | /// 17 | /// Queryable page 18 | /// 19 | /// 20 | /// 21 | /// 22 | /// 23 | /// 24 | public QueryablePage(IQueryable queryable, int currentPageNumber, int pageSize, int totalMemberCount, bool sourceIsFull = true) : base(sourceIsFull) 25 | { 26 | var skip = (currentPageNumber - 1) * pageSize; 27 | var state = new QueryEntryState(queryable, skip, pageSize); 28 | InitializeMetaInfo()(currentPageNumber)(pageSize)(totalMemberCount)(skip)(); 29 | base._initializeAction = InitializeMemberList()(state)(CurrentPageSize)(skip); 30 | } 31 | 32 | /// 33 | /// Queryable page 34 | /// 35 | /// 36 | /// 37 | /// 38 | /// 39 | public QueryablePage(IEnumerable enumerable, int currentPageNumber, int pageSize, int totalMembersCount) 40 | : this(enumerable.AsQueryable(), currentPageNumber, pageSize, totalMembersCount) { } 41 | 42 | /// 43 | /// Get empty page 44 | /// 45 | /// 46 | public static EmptyPage Empty() => new(); 47 | 48 | private Func>>> InitializeMetaInfo() => c => s => t => k => () => 49 | { 50 | // c = current page number 51 | // s = page size 52 | // t = total member count 53 | // k = skip 54 | var totalPageCount = (int) Math.Ceiling((double) t / (double) s); 55 | totalPageCount = totalPageCount < 0 ? 0 : totalPageCount; 56 | base.TotalPageCount = totalPageCount == 0 ? 1 : totalPageCount; 57 | base.TotalMemberCount = t; 58 | base.CurrentPageNumber = c; 59 | base.PageSize = s; 60 | base.CurrentPageSize = c == totalPageCount 61 | ? k == 0 62 | ? t 63 | : t % k 64 | : totalPageCount == 0 65 | ? 0 66 | : s; 67 | 68 | base.HasPrevious = c > 1; 69 | base.HasNext = c < base.TotalPageCount; 70 | }; 71 | 72 | private Func, Func>> InitializeMemberList() => state => s => k => () => 73 | { 74 | // s = page size 75 | // k = skip 76 | base._memberList = new List>(s); 77 | for (var i = 0; i < s; i++) 78 | { 79 | base._memberList.Add(new PageMember(state, i, ref k)); 80 | } 81 | }; 82 | } 83 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.Chloe/DotNetCore/Collections/Paginable/Extensions/SolidPageExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Chloe; 4 | using DotNetCore.Collections.Paginable.Internal; 5 | 6 | // ReSharper disable once CheckNamespace 7 | namespace DotNetCore.Collections.Paginable 8 | { 9 | /// 10 | /// Extensions for solid page for Chloe 11 | /// 12 | public static class SolidPageExtensions 13 | { 14 | /// 15 | /// Make original ChloeQueryable result to ChloePage collection. 16 | /// 17 | /// element type of your enumerable result 18 | /// ChloeQueryable 19 | /// limited member count 20 | /// 21 | public static PaginableChloeQuery ToPaginable(this IQuery query, int? limitedMemberCount = null) 22 | => PaginableChloeCollFactory.CreatePageSet(query, limitedMemberCount: limitedMemberCount); 23 | 24 | /// 25 | /// Make original ChloeQueryable result to ChloePage collection. 26 | /// 27 | /// element type of your enumerable result 28 | /// ChloeQueryable 29 | /// page size 30 | /// limited member count 31 | /// 32 | public static PaginableChloeQuery ToPaginable(this IQuery query, int pageSize, int? limitedMemberCount = null) 33 | => PaginableChloeCollFactory.CreatePageSet(query, pageSize, limitedMemberCount); 34 | 35 | /// 36 | /// Get specific page from original ChloeQueryable source 37 | /// 38 | /// element type of your ChloeQueryable source 39 | /// original ChloeQueryable source 40 | /// page number 41 | /// 42 | /// 43 | public static IPage GetPage(this IQuery query, int pageNumber, Func, IQuery> additionalQueryFunc = null) 44 | => GetPage(query, pageNumber, PaginableSettingsManager.Settings.DefaultPageSize, additionalQueryFunc); 45 | 46 | /// 47 | /// Get specific page from original ChloeQueryable source 48 | /// 49 | /// element type of your ChloeQueryable source 50 | /// original ChloeQueryable source 51 | /// page number 52 | /// page size 53 | /// 54 | /// 55 | public static IPage GetPage(this IQuery query, int pageNumber, int pageSize, Func, IQuery> additionalQueryFunc = null) 56 | { 57 | if (query is null) 58 | throw new ArgumentNullException(nameof(query), $"{nameof(query)} can not be null."); 59 | 60 | if (pageNumber < 0) 61 | throw new IndexOutOfRangeException($"{nameof(pageNumber)} can not be less than zero"); 62 | 63 | if (pageSize < 0) 64 | throw new IndexOutOfRangeException($"{nameof(pageSize)} can not be less than zero"); 65 | 66 | return new ChloePage(query, pageNumber, pageSize, ChloeHelper.Count(query), additionalQueryFunc); 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable/DotNetCore/Collections/Paginable/EnumerablePage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | // ReSharper disable RedundantCast 6 | // ReSharper disable RedundantBaseQualifier 7 | 8 | namespace DotNetCore.Collections.Paginable 9 | { 10 | /// 11 | /// Enumerable page 12 | /// 13 | /// 14 | public class EnumerablePage : PageBase 15 | { 16 | /// 17 | /// Enumerable page 18 | /// 19 | /// 20 | /// 21 | /// 22 | /// 23 | /// 24 | public EnumerablePage(IEnumerable enumerable, int currentPageNumber, int pageSize, int totalMemberCount, bool sourceIsFull = true) : base(sourceIsFull) 25 | { 26 | var skip = (currentPageNumber - 1) * pageSize; 27 | InitializeMetaInfo()(currentPageNumber)(pageSize)(totalMemberCount)(skip)(); 28 | base._initializeAction = InitializeMemberList()(enumerable)(CurrentPageSize)(skip); 29 | } 30 | 31 | /// 32 | /// Get empty page 33 | /// 34 | /// 35 | public static EmptyPage Empty() => new(); 36 | 37 | private Func>>> InitializeMetaInfo() => c => s => t => k => () => 38 | { 39 | // c = current page number 40 | // s = page size 41 | // t = total member count 42 | // k = skip 43 | var totalPageCount = (int) Math.Ceiling((double) t / (double) s); 44 | totalPageCount = totalPageCount < 0 ? 0 : totalPageCount; 45 | base.TotalPageCount = totalPageCount == 0 ? 1 : totalPageCount; 46 | base.TotalMemberCount = t; 47 | base.CurrentPageNumber = c; 48 | base.PageSize = s; 49 | base.CurrentPageSize = c == totalPageCount 50 | ? k == 0 51 | ? t 52 | : t % k 53 | : totalPageCount == 0 54 | ? 0 55 | : s; 56 | 57 | base.HasPrevious = c > 1; 58 | base.HasNext = c < base.TotalPageCount; 59 | }; 60 | 61 | private Func, Func>> InitializeMemberList() 62 | => array => s => k => () => 63 | { 64 | // s = current page size 65 | // k = skip 66 | base._memberList = new List>(s); 67 | if (array is IQueryable query) 68 | { 69 | var realQuery = query.Skip(k).Take(s).ToList(); 70 | var offset = 0; 71 | foreach (var item in realQuery) 72 | { 73 | base._memberList.Add(new PageMember(item, offset++, ref k)); 74 | } 75 | } 76 | else if (base.SourceIsFull) 77 | { 78 | for (var i = 0; i < s; i++) 79 | { 80 | base._memberList.Add(new PageMember(array.ElementAt(k + i), i, ref k)); 81 | } 82 | } 83 | else 84 | { 85 | for (var i = 0; i < s; i++) 86 | { 87 | base._memberList.Add(new PageMember(array.ElementAt(i), i, ref k)); 88 | } 89 | } 90 | }; 91 | } 92 | } -------------------------------------------------------------------------------- /tests/DotNetCore.Collections.Paginable.ConsoleTests/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace DotNetCore.Collections.Paginable.ConsoleTests 6 | { 7 | class Program 8 | { 9 | static void Main(string[] args) 10 | { 11 | List1Test(); 12 | 13 | List2Test(); 14 | 15 | List3Test(); 16 | 17 | List4Test(); 18 | 19 | Console.ReadKey(); 20 | 21 | } 22 | 23 | private static void List1Test() 24 | { 25 | var list1 = Enumerable.Range(0, 100); 26 | var paginableList1 = list1.ToPaginable(20); 27 | var page01 = paginableList1.GetPage(1); 28 | var page02 = paginableList1.GetPage(2); 29 | 30 | Console.WriteLine("===========e01=============="); 31 | 32 | for (var i = 0; i < page01.CurrentPageSize; i++) 33 | { 34 | Console.WriteLine($"{page01[i].ItemNumber}:{page01[i].Value}"); 35 | } 36 | 37 | Console.WriteLine("===========e02=============="); 38 | 39 | for (var i = 0; i < page02.CurrentPageSize; i++) 40 | { 41 | Console.WriteLine($"{page02[i].ItemNumber}:{page02[i].Value}"); 42 | } 43 | 44 | var metadata01 = page01.GetMetadata(); 45 | var metadata02 = page02.GetMetadata(); 46 | 47 | Console.WriteLine(metadata01); 48 | Console.WriteLine(metadata02); 49 | } 50 | 51 | private static void List2Test() 52 | { 53 | var list2 = Enumerable.Range(0, 100).AsQueryable(); 54 | var paginableList2 = list2.ToPaginable(20); 55 | var page11 = paginableList2.GetPage(1); 56 | var page12 = paginableList2.GetPage(2); 57 | 58 | 59 | Console.WriteLine("===========q01=============="); 60 | 61 | for (var i = 0; i < page11.CurrentPageSize; i++) 62 | { 63 | Console.WriteLine($"{page11[i].ItemNumber}:{page11[i].Value}"); 64 | } 65 | 66 | 67 | Console.WriteLine("===========q02=============="); 68 | 69 | for (var i = 0; i < page12.CurrentPageSize; i++) 70 | { 71 | Console.WriteLine($"{page12[i].ItemNumber}:{page12[i].Value}"); 72 | } 73 | 74 | var metadata11 = page11.GetMetadata(); 75 | var metadata12 = page12.GetMetadata(); 76 | 77 | Console.WriteLine(metadata11); 78 | Console.WriteLine(metadata12); 79 | } 80 | 81 | private static void List3Test() 82 | { 83 | var list1 = new List(); 84 | var paginableList1 = list1.ToPaginable(20); 85 | var page01 = paginableList1.GetPage(1); 86 | 87 | Console.WriteLine("===========e00=============="); 88 | 89 | for (var i = 0; i < page01.CurrentPageSize; i++) 90 | { 91 | Console.WriteLine($"{page01[i].ItemNumber}:{page01[i].Value}"); 92 | } 93 | 94 | var metadata01 = page01.GetMetadata(); 95 | 96 | Console.WriteLine(metadata01); 97 | } 98 | 99 | private static void List4Test() 100 | { 101 | var list1 = new List().AsQueryable(); 102 | var paginableList1 = list1.ToPaginable(20); 103 | var page01 = paginableList1.GetPage(1); 104 | 105 | Console.WriteLine("===========q00=============="); 106 | 107 | for (var i = 0; i < page01.CurrentPageSize; i++) 108 | { 109 | Console.WriteLine($"{page01[i].ItemNumber}:{page01[i].Value}"); 110 | } 111 | 112 | var metadata01 = page01.GetMetadata(); 113 | 114 | Console.WriteLine(metadata01); 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /sample/Sample.EfCore/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using DotNetCore.Collections.Paginable; 5 | using Microsoft.EntityFrameworkCore; 6 | 7 | namespace Sample.EfCore 8 | { 9 | class Program 10 | { 11 | static void Main(string[] args) 12 | { 13 | //注意,本示例仅用于演示 api 如何使用,实际上并不能运行 14 | //Note: Such example is only used to demonstrate how the apis can be used, actually it cannot work. 15 | 16 | //... 17 | 18 | using (var ctx = new DemoContext()) 19 | { 20 | var a = ctx.DemoModels.GetPage(5, 20); 21 | var b = ctx.DemoModels.Where(x => x.IsValid).GetPage(2, 20); 22 | var c = ctx.DemoModels.Include(l => l.Items).GetPage(5, 20); 23 | var d = ctx.DemoModels.Include(l => l.Items).Where(x => x.IsValid).GetPage(2, 20); 24 | 25 | foreach (var itemOfA in a) 26 | { 27 | var indexInDb = itemOfA.ItemNumber; 28 | var indexInResult = itemOfA.Offset; 29 | var actuallyValue = itemOfA.Value; // an instance of type DemoModel. 30 | } 31 | 32 | foreach (var itemOfC in c.ToOriginalItems()) // to get a list of DemoModel you have requested 33 | { 34 | //now, itemOfC is an instance of type DemoModel. 35 | } 36 | } 37 | 38 | using (var ctx = new DemoContext()) 39 | { 40 | var e = ctx.DemoModels.ToPaginable(20); 41 | 42 | var howManyItemsInDb = e.MemberCount; 43 | var howManyPagesYouCanGet = e.PageCount; 44 | var howManyItemsDoYouWantPerPage = e.PageSize; 45 | 46 | var f = e.GetPage(2); //get second page (which index is 1) 47 | 48 | var realPageNumberYouHaveRequested = f.CurrentPageNumber; 49 | var countOfPageYouWantToGet = f.PageSize; 50 | var realCountOfItemsYouHaveGot = f.CurrentPageSize; // also means total member count in such page 51 | 52 | var realCountOfItemsInDb = f.TotalMemberCount; 53 | var realCountOfPagesYouCanGet = f.TotalPageCount; 54 | 55 | var originResults = f.ToOriginalItems(); // Get all items you have requested. 56 | 57 | foreach (var originItem in originResults) 58 | { 59 | //... 60 | } 61 | 62 | foreach (var itemInPage in f) 63 | { 64 | var indexInDb = itemInPage.ItemNumber; 65 | var indexInResult = itemInPage.Offset; 66 | var actuallyValue = itemInPage.Value; // an instance of type DemoModel. 67 | } 68 | 69 | } 70 | 71 | 72 | using (var ctx = new DemoContext()) 73 | { 74 | var g = ctx.DemoModels.ToPaginable(20, 1000); 75 | // it means that, there are 20 item in each page, and only query the first 1000 records 76 | } 77 | } 78 | 79 | public class DemoContext : DbContext 80 | { 81 | //... 82 | 83 | public virtual DbSet DemoModels { get; set; } 84 | public virtual DbSet DemoModelItems { get; set; } 85 | } 86 | 87 | public class DemoModel 88 | { 89 | public Guid Id { get; set; } 90 | public List Items { get; set; } 91 | public bool IsValid { get; set; } 92 | } 93 | 94 | public class DemoModelItem 95 | { 96 | public Guid Id { get; set; } 97 | public Guid FatherId { get; set; } 98 | public string Name { get; set; } 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /sample/Sample.Ef/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data.Entity; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using DotNetCore.Collections.Paginable; 8 | 9 | namespace Sample.Ef 10 | { 11 | class Program 12 | { 13 | static void Main(string[] args) 14 | { 15 | //注意,本示例仅用于演示 api 如何使用,实际上并不能运行 16 | //Note: Such example is only used to demonstrate how the apis can be used, actually it cannot work. 17 | 18 | //... 19 | 20 | using (var ctx = new DemoContext()) 21 | { 22 | var a = ctx.DemoModels.GetPage(5, 20); 23 | var b = ctx.DemoModels.Where(x => x.IsValid).GetPage(2, 20); 24 | var c = ctx.DemoModels.Include(l => l.Items).GetPage(5, 20); 25 | var d = ctx.DemoModels.Include(l => l.Items).Where(x => x.IsValid).GetPage(2, 20); 26 | 27 | foreach (var itemOfA in a) 28 | { 29 | var indexInDb = itemOfA.ItemNumber; 30 | var indexInResult = itemOfA.Offset; 31 | var actuallyValue = itemOfA.Value; // an instance of type DemoModel. 32 | } 33 | 34 | foreach (var itemOfC in c.ToOriginalItems()) // to get a list of DemoModel you have requested 35 | { 36 | //now, itemOfC is an instance of type DemoModel. 37 | } 38 | } 39 | 40 | using (var ctx = new DemoContext()) 41 | { 42 | var e = ctx.DemoModels.ToPaginable(20); 43 | 44 | var howManyItemsInDb = e.MemberCount; 45 | var howManyPagesYouCanGet = e.PageCount; 46 | var howManyItemsDoYouWantPerPage = e.PageSize; 47 | 48 | var f = e.GetPage(2); //get second page (which index is 1) 49 | 50 | var realPageNumberYouHaveRequested = f.CurrentPageNumber; 51 | var countOfPageYouWantToGet = f.PageSize; 52 | var realCountOfItemsYouHaveGot = f.CurrentPageSize; // also means total member count in such page 53 | 54 | var realCountOfItemsInDb = f.TotalMemberCount; 55 | var realCountOfPagesYouCanGet = f.TotalPageCount; 56 | 57 | var originResults = f.ToOriginalItems(); // Get all items you have requested. 58 | 59 | foreach (var originItem in originResults) 60 | { 61 | //... 62 | } 63 | 64 | foreach (var itemInPage in f) 65 | { 66 | var indexInDb = itemInPage.ItemNumber; 67 | var indexInResult = itemInPage.Offset; 68 | var actuallyValue = itemInPage.Value; // an instance of type DemoModel. 69 | } 70 | 71 | } 72 | 73 | 74 | using (var ctx = new DemoContext()) 75 | { 76 | var g = ctx.DemoModels.ToPaginable(20, 1000); 77 | // it means that, there are 20 item in each page, and only query the first 1000 records 78 | } 79 | } 80 | 81 | public class DemoContext : DbContext 82 | { 83 | //... 84 | 85 | public virtual DbSet DemoModels { get; set; } 86 | public virtual DbSet DemoModelItems { get; set; } 87 | } 88 | 89 | public class DemoModel 90 | { 91 | public Guid Id { get; set; } 92 | public List Items { get; set; } 93 | public bool IsValid { get; set; } 94 | } 95 | 96 | public class DemoModelItem 97 | { 98 | public Guid Id { get; set; } 99 | public Guid FatherId { get; set; } 100 | public string Name { get; set; } 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable/DotNetCore/Collections/Paginable/Internal/PaginableCollectionFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | // ReSharper disable PossibleMultipleEnumeration 6 | // ReSharper disable RedundantCast 7 | 8 | namespace DotNetCore.Collections.Paginable.Internal 9 | { 10 | internal static class PaginableCollectionFactory 11 | { 12 | /// 13 | /// Get real member count
. 14 | /// first parameter(l) means limitedMemberCount
, 15 | /// second parameter(c) means count. 16 | ///
17 | /// 18 | private static Func> GetRealMemberCountFunc() 19 | => l => c => l.IsValid() && l.HasValue ? l.Value > c ? c : l.Value : c; 20 | 21 | /// 22 | /// Get real page count
. 23 | /// first parameter(m) means real member count, which has been gotten from
, 24 | /// second parameter(s) means page size. 25 | ///
26 | /// 27 | private static Func> GetRealPageCountFunc() 28 | => m => s => (int) Math.Ceiling((double) m / (double) s); 29 | 30 | /// 31 | /// Make enumerable result to EnumerablePage collection 32 | /// 33 | /// element type of your enumerable result 34 | /// orgin enumerable result 35 | /// page size 36 | /// limited member count 37 | /// 38 | public static PaginableEnumerable CreatePageSet(IEnumerable enumerable, int? pageSize = null, int? limitedMemberCount = null) 39 | { 40 | if (enumerable is null) 41 | throw new ArgumentNullException(nameof(enumerable)); 42 | 43 | pageSize ??= PaginableSettingsManager.Settings.DefaultPageSize; 44 | 45 | var size = pageSize.Value; 46 | var realMemberCount = GetRealMemberCountFunc()(limitedMemberCount)(enumerable.Count()); 47 | var realPageCount = GetRealPageCountFunc()(realMemberCount)(size); 48 | 49 | return limitedMemberCount.IsValid() && limitedMemberCount.HasValue 50 | ? new PaginableEnumerable(enumerable, size, realPageCount, realMemberCount, limitedMemberCount.Value) 51 | : new PaginableEnumerable(enumerable, size, realPageCount, realMemberCount); 52 | } 53 | 54 | /// 55 | /// Make queryable source to QueryablePage collection 56 | /// 57 | /// element type of your queryable source 58 | /// orgin queryable result 59 | /// page size 60 | /// limited member count 61 | /// 62 | public static PaginableQueryable CreatePageSet(IQueryable queryable, int? pageSize = null, int? limitedMemberCount = null) 63 | { 64 | if (queryable is null) 65 | throw new ArgumentNullException(nameof(queryable)); 66 | 67 | pageSize ??= PaginableSettingsManager.Settings.DefaultPageSize; 68 | 69 | var size = pageSize.Value; 70 | var realMemberCount = GetRealMemberCountFunc()(limitedMemberCount)(queryable.Count()); 71 | var realPageCount = GetRealPageCountFunc()(realMemberCount)(size); 72 | 73 | return limitedMemberCount.IsValid() && limitedMemberCount.HasValue 74 | ? new PaginableQueryable(queryable, size, realPageCount, realMemberCount, limitedMemberCount.Value) 75 | : new PaginableQueryable(queryable, size, realPageCount, realMemberCount); 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.DosOrm/DotNetCore/Collections/Paginable/Extensions/SolidPageExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Dos.ORM; 3 | using DotNetCore.Collections.Paginable.Internal; 4 | 5 | // ReSharper disable once CheckNamespace 6 | namespace DotNetCore.Collections.Paginable 7 | { 8 | /// 9 | /// Extensions for solid page for DosORM 10 | /// 11 | public static class SolidPageExtensions 12 | { 13 | /// 14 | /// Make original DosQueryable result to DosPage collection. 15 | /// 16 | /// element type of your enumerable result 17 | /// DosQueryable 18 | /// limited member count 19 | /// 20 | /// 21 | public static PaginableDosQuery ToPaginable(this FromSection query, int? limitedMemberCount = null, 22 | Func, FromSection> additionalQueryFunc = null) where T : Entity 23 | => PaginableDosCollFactory.CreatePageSet(query, limitedMemberCount: limitedMemberCount, additionalQueryFunc: additionalQueryFunc); 24 | 25 | /// 26 | /// Make original DosQueryable result to DosPage collection. 27 | /// 28 | /// element type of your enumerable result 29 | /// DosQueryable 30 | /// page size 31 | /// limited member count 32 | /// 33 | /// 34 | public static PaginableDosQuery ToPaginable(this FromSection query, int pageSize, int? limitedMemberCount = null, 35 | Func, FromSection> additionalQueryFunc = null) where T : Entity 36 | => PaginableDosCollFactory.CreatePageSet(query, pageSize, limitedMemberCount, additionalQueryFunc: additionalQueryFunc); 37 | 38 | /// 39 | /// Get specific page from original DosQueryable source 40 | /// 41 | /// element type of your DosQueryable source 42 | /// original DosQueryable source 43 | /// page number 44 | /// 45 | /// 46 | public static IPage GetPage(this FromSection query, int pageNumber, Func, FromSection> additionalQueryFunc = null) where T : Entity 47 | => GetPage(query, pageNumber, PaginableSettingsManager.Settings.DefaultPageSize, additionalQueryFunc: additionalQueryFunc); 48 | 49 | /// 50 | /// Get specific page from original DosQueryable source 51 | /// 52 | /// element type of your DosQueryable source 53 | /// original DosQueryable source 54 | /// page number 55 | /// page size 56 | /// 57 | /// 58 | public static IPage GetPage(this FromSection query, int pageNumber, int pageSize, Func, FromSection> additionalQueryFunc = null) 59 | where T : Entity 60 | { 61 | if (query is null) 62 | throw new ArgumentNullException(nameof(query), $"{nameof(query)} can not be null."); 63 | 64 | if (pageNumber < 0) 65 | throw new IndexOutOfRangeException($"{nameof(pageNumber)} can not be less than zero"); 66 | 67 | if (pageSize < 0) 68 | throw new IndexOutOfRangeException($"{nameof(pageSize)} can not be less than zero"); 69 | 70 | return new DosPage(query, pageNumber, pageSize, DosHelper.Count(query), additionalQueryFunc: additionalQueryFunc); 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.EntityFramework/DotNetCore.Collections.Paginable.EntityFramework.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | DotNetCore.Collections.Paginable.EntityFramework 5 | 6 | 7 | 8 | 9 | Extensions for solid page for EntityFramework 10 | 11 | 12 | 13 | 14 | Make original query result to QueryablePage collection. 15 | 16 | element type of your enumerable result 17 | DbSet source 18 | limited member count 19 | 20 | 21 | 22 | 23 | Make original query result to QueryablePage collection. 24 | 25 | element type of your enumerable result 26 | DbSet source 27 | page size 28 | limited member count 29 | 30 | 31 | 32 | 33 | Get specific page from original EfCore DbSet`1 source 34 | 35 | element type of your EfCore DbSet`1 source 36 | DbSet source 37 | page number 38 | 39 | 40 | 41 | 42 | Get specific page from original EfCore DbSet`1 source 43 | 44 | element type of your EfCore DbSet`1 source 45 | DbSet source 46 | page number 47 | page size 48 | 49 | 50 | 51 | 52 | Get specific page from original EfCore DbSet`1 source 53 | 54 | element type of your EfCore DbSet`1 source 55 | DbSet source 56 | Predicate 57 | page number 58 | 59 | 60 | 61 | 62 | Get specific page from original EfCore DbSet`1 source 63 | 64 | element type of your EfCore DbSet`1 source 65 | DbSet source 66 | Predicate 67 | page number 68 | page size 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.EntityFramework/DotNetCore/Collections/Paginable/SolidPageExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data.Entity; 3 | using System.Linq; 4 | using System.Linq.Expressions; 5 | 6 | namespace DotNetCore.Collections.Paginable 7 | { 8 | /// 9 | /// Extensions for solid page for EntityFramework 10 | /// 11 | public static class SolidPageExtensions 12 | { 13 | /// 14 | /// Make original query result to QueryablePage collection. 15 | /// 16 | /// element type of your enumerable result 17 | /// DbSet source 18 | /// limited member count 19 | /// 20 | public static PaginableQueryable ToPaginable(this DbSet source, int? limitedMemberCount = null) where T : class 21 | => source.AsQueryable().ToPaginable(limitedMemberCount: limitedMemberCount); 22 | 23 | /// 24 | /// Make original query result to QueryablePage collection. 25 | /// 26 | /// element type of your enumerable result 27 | /// DbSet source 28 | /// page size 29 | /// limited member count 30 | /// 31 | public static PaginableQueryable ToPaginable(this DbSet source, int pageSize, int? limitedMemberCount = null) where T : class 32 | => source.AsQueryable().ToPaginable(pageSize, limitedMemberCount); 33 | 34 | /// 35 | /// Get specific page from original EfCore DbSet`1 source 36 | /// 37 | /// element type of your EfCore DbSet`1 source 38 | /// DbSet source 39 | /// page number 40 | /// 41 | public static IPage GetPage(this DbSet source, int pageNumber) where T : class 42 | => source.AsQueryable().GetPage(pageNumber); 43 | 44 | /// 45 | /// Get specific page from original EfCore DbSet`1 source 46 | /// 47 | /// element type of your EfCore DbSet`1 source 48 | /// DbSet source 49 | /// page number 50 | /// page size 51 | /// 52 | public static IPage GetPage(this DbSet source, int pageNumber, int pageSize) where T : class 53 | => source.AsQueryable().GetPage(pageNumber, pageSize); 54 | 55 | /// 56 | /// Get specific page from original EfCore DbSet`1 source 57 | /// 58 | /// element type of your EfCore DbSet`1 source 59 | /// DbSet source 60 | /// Predicate 61 | /// page number 62 | /// 63 | public static IPage GetPage(this DbSet source, Expression> predicate, int pageNumber) where T : class 64 | => source.Where(predicate).GetPage(pageNumber); 65 | 66 | /// 67 | /// Get specific page from original EfCore DbSet`1 source 68 | /// 69 | /// element type of your EfCore DbSet`1 source 70 | /// DbSet source 71 | /// Predicate 72 | /// page number 73 | /// page size 74 | /// 75 | public static IPage GetPage(this DbSet source, Expression> predicate, int pageNumber, int pageSize) where T : class 76 | => source.Where(predicate).GetPage(pageNumber, pageSize); 77 | } 78 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.EntityFrameworkCore/DotNetCore/Collections/Paginable/SolidPageExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Linq.Expressions; 4 | using Microsoft.EntityFrameworkCore; 5 | 6 | namespace DotNetCore.Collections.Paginable 7 | { 8 | /// 9 | /// Extensions for solid page for EntityFrameworkCore 10 | /// 11 | public static class SolidPageExtensions 12 | { 13 | /// 14 | /// Make original query result to QueryablePage collection. 15 | /// 16 | /// element type of your enumerable result 17 | /// DbSet source 18 | /// limited member count 19 | /// 20 | public static PaginableQueryable ToPaginable(this DbSet source, int? limitedMemberCount = null) where T : class 21 | => source.AsQueryable().ToPaginable(limitedMemberCount: limitedMemberCount); 22 | 23 | /// 24 | /// Make original query result to QueryablePage collection. 25 | /// 26 | /// element type of your enumerable result 27 | /// DbSet source 28 | /// page size 29 | /// limited member count 30 | /// 31 | public static PaginableQueryable ToPaginable(this DbSet source, int pageSize, int? limitedMemberCount = null) where T : class 32 | => source.AsQueryable().ToPaginable(pageSize, limitedMemberCount); 33 | 34 | /// 35 | /// Get specific page from original EfCore DbSet`1 source 36 | /// 37 | /// element type of your EfCore DbSet`1 source 38 | /// DbSet source 39 | /// page number 40 | /// 41 | public static IPage GetPage(this DbSet source, int pageNumber) where T : class 42 | => source.AsQueryable().GetPage(pageNumber); 43 | 44 | /// 45 | /// Get specific page from original EfCore DbSet`1 source 46 | /// 47 | /// element type of your EfCore DbSet`1 source 48 | /// DbSet source 49 | /// page number 50 | /// page size 51 | /// 52 | public static IPage GetPage(this DbSet source, int pageNumber, int pageSize) where T : class 53 | => source.AsQueryable().GetPage(pageNumber, pageSize); 54 | 55 | /// 56 | /// Get specific page from original EfCore DbSet`1 source 57 | /// 58 | /// element type of your EfCore DbSet`1 source 59 | /// DbSet source 60 | /// Predicate 61 | /// page number 62 | /// 63 | public static IPage GetPage(this DbSet source, Expression> predicate, int pageNumber) where T : class 64 | => source.Where(predicate).GetPage(pageNumber); 65 | 66 | /// 67 | /// Get specific page from original EfCore DbSet`1 source 68 | /// 69 | /// element type of your EfCore DbSet`1 source 70 | /// DbSet source 71 | /// Predicate 72 | /// page number 73 | /// page size 74 | /// 75 | public static IPage GetPage(this DbSet source, Expression> predicate, int pageNumber, int pageSize) where T : class 76 | => source.Where(predicate).GetPage(pageNumber, pageSize); 77 | } 78 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.EntityFrameworkCore/DotNetCore.Collections.Paginable.EntityFrameworkCore.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | DotNetCore.Collections.Paginable.EntityFrameworkCore 5 | 6 | 7 | 8 | 9 | Extensions for solid page for EntityFrameworkCore 10 | 11 | 12 | 13 | 14 | Make original query result to QueryablePage collection. 15 | 16 | element type of your enumerable result 17 | DbSet source 18 | limited member count 19 | 20 | 21 | 22 | 23 | Make original query result to QueryablePage collection. 24 | 25 | element type of your enumerable result 26 | DbSet source 27 | page size 28 | limited member count 29 | 30 | 31 | 32 | 33 | Get specific page from original EfCore DbSet`1 source 34 | 35 | element type of your EfCore DbSet`1 source 36 | DbSet source 37 | page number 38 | 39 | 40 | 41 | 42 | Get specific page from original EfCore DbSet`1 source 43 | 44 | element type of your EfCore DbSet`1 source 45 | DbSet source 46 | page number 47 | page size 48 | 49 | 50 | 51 | 52 | Get specific page from original EfCore DbSet`1 source 53 | 54 | element type of your EfCore DbSet`1 source 55 | DbSet source 56 | Predicate 57 | page number 58 | 59 | 60 | 61 | 62 | Get specific page from original EfCore DbSet`1 source 63 | 64 | element type of your EfCore DbSet`1 source 65 | DbSet source 66 | Predicate 67 | page number 68 | page size 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /tests/DotNetCore.Collections.Paginable.DbTests/EfCoreTests.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using DotNetCore.Collections.Paginable.DbTests.Models; 3 | using Microsoft.EntityFrameworkCore; 4 | using Shouldly; 5 | using Xunit; 6 | 7 | namespace DotNetCore.Collections.Paginable.DbTests 8 | { 9 | public class EfCoreTests 10 | { 11 | internal static readonly string ConnectionString = @"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=D:\Development\Collections\tests\DotNetCore.Collections.Paginable.DbTests\DataSource\Samples.mdf;Integrated Security=True"; 12 | 13 | [Fact] 14 | public void GetPageTest() 15 | { 16 | using (var db = new Int32DbContext()) 17 | { 18 | var page = db.Int32Samples.Where(x => x.Id > 0).GetPage(1, 9); 19 | page.TotalPageCount.ShouldBe(24); 20 | page.TotalMemberCount.ShouldBe(210); 21 | page.CurrentPageNumber.ShouldBe(1); 22 | page.PageSize.ShouldBe(9); 23 | page.CurrentPageSize.ShouldBe(9); 24 | page.HasNext.ShouldBeTrue(); 25 | page.HasPrevious.ShouldBeFalse(); 26 | 27 | page[0].Value.Id.ShouldBe(1); 28 | page[1].Value.Id.ShouldBe(2); 29 | page[2].Value.Id.ShouldBe(3); 30 | page[3].Value.Id.ShouldBe(4); 31 | page[4].Value.Id.ShouldBe(5); 32 | page[5].Value.Id.ShouldBe(6); 33 | page[6].Value.Id.ShouldBe(7); 34 | page[7].Value.Id.ShouldBe(8); 35 | page[8].Value.Id.ShouldBe(9); 36 | } 37 | } 38 | 39 | [Fact] 40 | public void GetPageFromDbSetTest() 41 | { 42 | using (var db = new Int32DbContext()) 43 | { 44 | var page = db.Int32Samples.GetPage(1, 9); 45 | page.TotalPageCount.ShouldBe(24); 46 | page.TotalMemberCount.ShouldBe(210); 47 | page.CurrentPageNumber.ShouldBe(1); 48 | page.PageSize.ShouldBe(9); 49 | page.CurrentPageSize.ShouldBe(9); 50 | page.HasNext.ShouldBeTrue(); 51 | page.HasPrevious.ShouldBeFalse(); 52 | 53 | page[0].Value.Id.ShouldBe(1); 54 | page[1].Value.Id.ShouldBe(2); 55 | page[2].Value.Id.ShouldBe(3); 56 | page[3].Value.Id.ShouldBe(4); 57 | page[4].Value.Id.ShouldBe(5); 58 | page[5].Value.Id.ShouldBe(6); 59 | page[6].Value.Id.ShouldBe(7); 60 | page[7].Value.Id.ShouldBe(8); 61 | page[8].Value.Id.ShouldBe(9); 62 | } 63 | } 64 | 65 | [Fact] 66 | public void GetPageFromDbSet2Test() 67 | { 68 | using (var db = new Int32DbContext()) 69 | { 70 | var page = db.Int32Samples.GetPage(x => x.Id > 0, 1, 9); 71 | page.TotalPageCount.ShouldBe(24); 72 | page.TotalMemberCount.ShouldBe(210); 73 | page.CurrentPageNumber.ShouldBe(1); 74 | page.PageSize.ShouldBe(9); 75 | page.CurrentPageSize.ShouldBe(9); 76 | page.HasNext.ShouldBeTrue(); 77 | page.HasPrevious.ShouldBeFalse(); 78 | 79 | page[0].Value.Id.ShouldBe(1); 80 | page[1].Value.Id.ShouldBe(2); 81 | page[2].Value.Id.ShouldBe(3); 82 | page[3].Value.Id.ShouldBe(4); 83 | page[4].Value.Id.ShouldBe(5); 84 | page[5].Value.Id.ShouldBe(6); 85 | page[6].Value.Id.ShouldBe(7); 86 | page[7].Value.Id.ShouldBe(8); 87 | page[8].Value.Id.ShouldBe(9); 88 | } 89 | } 90 | 91 | public class Int32DbContext : DbContext 92 | { 93 | public virtual DbSet Int32Samples { get; set; } 94 | 95 | protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 96 | { 97 | optionsBuilder.UseSqlServer(EfCoreTests.ConnectionString); 98 | } 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.SqlKata/DotNetCore/Collections/Paginable/Extensions/SolidPageExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using DotNetCore.Collections.Paginable.Internal; 4 | using SqlKata; 5 | 6 | // ReSharper disable once CheckNamespace 7 | namespace DotNetCore.Collections.Paginable 8 | { 9 | /// 10 | /// Extensions for solid page for sqlkata 11 | /// 12 | public static class SolidPageExtensions 13 | { 14 | /// 15 | /// Make original SqlKata.Query result to SqlKataPage collection. 16 | /// 17 | /// element type of your enumerable result 18 | /// SqlKata.Query 19 | /// limited member count 20 | /// 21 | public static PaginableSqlKataQuery ToPaginable(this Query query, int? limitedMemberCount = null) 22 | => PaginableSqlKataCollFactory.CreatePageSet(query, limitedMemberCount: limitedMemberCount); 23 | 24 | /// 25 | /// Make original SqlKata.Query result to SqlKataPage collection. 26 | /// 27 | /// element type of your enumerable result 28 | /// SqlKata.Query 29 | /// page size 30 | /// limited member count 31 | /// 32 | public static PaginableSqlKataQuery ToPaginable(this Query query, int pageSize, int? limitedMemberCount = null) 33 | => PaginableSqlKataCollFactory.CreatePageSet(query, pageSize, limitedMemberCount); 34 | 35 | /// 36 | /// Get specific page from original SqlKata.Query source 37 | /// 38 | /// element type of your SqlKata.Query source 39 | /// original SqlKata.Query source 40 | /// 41 | /// 42 | public static IPage GetPage(this Query query, int pageNumber) 43 | => GetPage(query, pageNumber, PaginableSettingsManager.Settings.DefaultPageSize); 44 | 45 | /// 46 | /// Get specific page from original SqlKata.Query source 47 | /// 48 | /// element type of your SqlKata.Query source 49 | /// original SqlKata.Query source 50 | /// page number 51 | /// page size 52 | /// 53 | public static IPage GetPage(this Query query, int pageNumber, int pageSize) 54 | { 55 | if (query is null) 56 | throw new ArgumentNullException(nameof(query), $"{nameof(query)} can not be null."); 57 | 58 | if (pageNumber < 0) 59 | throw new IndexOutOfRangeException($"{nameof(pageNumber)} can not be less than zero"); 60 | 61 | if (pageSize < 0) 62 | throw new IndexOutOfRangeException($"{nameof(pageSize)} can not be less than zero"); 63 | 64 | return new SqlKataPage(query, pageNumber, pageSize, SqlKataHelper.Count(query)); 65 | } 66 | 67 | /// 68 | /// Get specific page from original SqlKata.Query source 69 | /// 70 | /// element type of your SqlKata.Query source 71 | /// original SqlKata.Query source 72 | /// 73 | /// 74 | public static Task> GetPageAsync(this Query query, int pageNumber) 75 | => GetPageAsync(query, pageNumber, PaginableSettingsManager.Settings.DefaultPageSize); 76 | 77 | /// 78 | /// Get specific page from original SqlKata.Query source 79 | /// 80 | /// element type of your SqlKata.Query source 81 | /// original SqlKata.Query source 82 | /// page number 83 | /// page size 84 | /// 85 | public static async Task> GetPageAsync(this Query query, int pageNumber, int pageSize) 86 | { 87 | if (query is null) 88 | throw new ArgumentNullException(nameof(query), $"{nameof(query)} can not be null."); 89 | 90 | if (pageNumber < 0) 91 | throw new IndexOutOfRangeException($"{nameof(pageNumber)} can not be less than zero"); 92 | 93 | if (pageSize < 0) 94 | throw new IndexOutOfRangeException($"{nameof(pageSize)} can not be less than zero"); 95 | 96 | return new SqlKataPage(query, pageNumber, pageSize, await SqlKataHelper.CountAsync(query)); 97 | } 98 | } 99 | } -------------------------------------------------------------------------------- /tests/DotNetCore.Collections.Paginable.Tests/GetPageForQueryTest.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using DotNetCore.Collections.Paginable.Tests.Models; 4 | using Shouldly; 5 | using Xunit; 6 | 7 | namespace DotNetCore.Collections.Paginable.Tests { 8 | public class GetPageForQueryTest { 9 | 10 | private IQueryable EmptyQueryForStudents { get; set; } 11 | private IQueryable OneItemForStudents { get; set; } 12 | private IQueryable EightItemsForStudents { get; set; } 13 | 14 | public GetPageForQueryTest() { 15 | EmptyQueryForStudents = new List().AsQueryable(); 16 | OneItemForStudents = new List {new Student {Id = 1, Name = "Alex"}}.AsQueryable(); 17 | EightItemsForStudents = new List { 18 | new Student {Id = 2, Name = "Zhaomin"}, 19 | new Student {Id = 3, Name = "Zhaomin"}, 20 | new Student {Id = 4, Name = "Zhaomin"}, 21 | new Student {Id = 5, Name = "Zhaomin"}, 22 | new Student {Id = 6, Name = "Zhaomin"}, 23 | new Student {Id = 7, Name = "Zhaomin"}, 24 | new Student {Id = 8, Name = "Zhaomin"}, 25 | new Student {Id = 9, Name = "Zhaomin"}, 26 | }.AsQueryable(); 27 | } 28 | 29 | [Fact] 30 | public void EmptyQueryTest() { 31 | var page = EmptyQueryForStudents.GetPage(1, 9); 32 | page.TotalPageCount.ShouldBe(1); 33 | page.TotalMemberCount.ShouldBe(0); 34 | page.CurrentPageNumber.ShouldBe(1); 35 | page.PageSize.ShouldBe(9); 36 | page.CurrentPageSize.ShouldBe(0);//应该是0 37 | page.HasNext.ShouldBeFalse(); 38 | page.HasPrevious.ShouldBeFalse(); 39 | } 40 | 41 | [Fact] 42 | public void EmptyQueryToOriginTest() { 43 | var page = EmptyQueryForStudents.GetPage(1, 9); 44 | var origins = page.ToOriginalItems(); 45 | origins.ShouldNotBeNull(); 46 | origins.ShouldBeEmpty(); 47 | 48 | var counter = 0; 49 | foreach (var item in origins) counter++; 50 | counter.ShouldBe(0); 51 | } 52 | 53 | [Fact] 54 | public void OneItemTest() { 55 | var page = OneItemForStudents.GetPage(1, 9); 56 | page.TotalPageCount.ShouldBe(1); 57 | page.TotalMemberCount.ShouldBe(1); 58 | page.CurrentPageNumber.ShouldBe(1); 59 | page.PageSize.ShouldBe(9); 60 | page.CurrentPageSize.ShouldBe(1); 61 | page.HasNext.ShouldBeFalse(); 62 | page.HasPrevious.ShouldBeFalse(); 63 | } 64 | 65 | [Fact] 66 | public void OneItemToOriginTest() { 67 | var page = OneItemForStudents.GetPage(1, 9); 68 | var origins = page.ToOriginalItems(); 69 | origins.ShouldNotBeNull(); 70 | origins.Count().ShouldBe(1); 71 | 72 | var counter = 0; 73 | foreach (var item in origins) counter++; 74 | counter.ShouldBe(1); 75 | } 76 | 77 | [Fact] 78 | public void OnePageTest() { 79 | var page = EightItemsForStudents.GetPage(1, 9); 80 | page.TotalPageCount.ShouldBe(1); 81 | page.TotalMemberCount.ShouldBe(8); 82 | page.CurrentPageNumber.ShouldBe(1); 83 | page.PageSize.ShouldBe(9); 84 | page.CurrentPageSize.ShouldBe(8); 85 | page.HasNext.ShouldBeFalse(); 86 | page.HasPrevious.ShouldBeFalse(); 87 | } 88 | 89 | [Fact] 90 | public void OnePageoOriginTest() { 91 | var page = EightItemsForStudents.GetPage(1, 9); 92 | var origins = page.ToOriginalItems(); 93 | origins.ShouldNotBeNull(); 94 | origins.Count().ShouldBe(8); 95 | 96 | var counter = 0; 97 | foreach (var item in origins) counter++; 98 | counter.ShouldBe(8); 99 | } 100 | 101 | [Fact] 102 | public void SeveralPagesTest() { 103 | var page = EightItemsForStudents.GetPage(1, 2); 104 | page.TotalPageCount.ShouldBe(4); 105 | page.TotalMemberCount.ShouldBe(8); 106 | page.CurrentPageNumber.ShouldBe(1); 107 | page.PageSize.ShouldBe(2); 108 | page.CurrentPageSize.ShouldBe(2); 109 | page.HasNext.ShouldBeTrue(); 110 | page.HasPrevious.ShouldBeFalse(); 111 | } 112 | 113 | [Fact] 114 | public void SeveralPagesOriginTest() { 115 | var page = EightItemsForStudents.GetPage(1, 2); 116 | var origins = page.ToOriginalItems(); 117 | origins.ShouldNotBeNull(); 118 | origins.Count().ShouldBe(2); 119 | 120 | var counter = 0; 121 | foreach (var item in origins) counter++; 122 | counter.ShouldBe(2); 123 | } 124 | 125 | } 126 | } -------------------------------------------------------------------------------- /tests/DotNetCore.Collections.Paginable.DbTests/NhCoreTests.cs: -------------------------------------------------------------------------------- 1 | using DotNetCore.Collections.Paginable.DbTests.Models; 2 | using FluentNHibernate.Cfg; 3 | using FluentNHibernate.Cfg.Db; 4 | using FluentNHibernate.Mapping; 5 | using NHibernate; 6 | using NHibernate.Tool.hbm2ddl; 7 | using Shouldly; 8 | using Xunit; 9 | 10 | namespace DotNetCore.Collections.Paginable.DbTests 11 | { 12 | public class NhCoreTests 13 | { 14 | internal static readonly string ConnectionString = @"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=D:\Development\Collections\tests\DotNetCore.Collections.Paginable.DbTests\DataSource\Samples.mdf;Integrated Security=True"; 15 | 16 | [Fact] 17 | public void GetPageTest() 18 | { 19 | using (var session = NhHelper.OpenSession()) 20 | { 21 | var page = session.QueryOver().GetPage(1, 9); 22 | page.TotalPageCount.ShouldBe(24); 23 | page.TotalMemberCount.ShouldBe(210); 24 | page.CurrentPageNumber.ShouldBe(1); 25 | page.PageSize.ShouldBe(9); 26 | page.CurrentPageSize.ShouldBe(9); 27 | page.HasNext.ShouldBeTrue(); 28 | page.HasPrevious.ShouldBeFalse(); 29 | 30 | page[0].Value.Id.ShouldBe(1); 31 | page[1].Value.Id.ShouldBe(2); 32 | page[2].Value.Id.ShouldBe(3); 33 | page[3].Value.Id.ShouldBe(4); 34 | page[4].Value.Id.ShouldBe(5); 35 | page[5].Value.Id.ShouldBe(6); 36 | page[6].Value.Id.ShouldBe(7); 37 | page[7].Value.Id.ShouldBe(8); 38 | page[8].Value.Id.ShouldBe(9); 39 | } 40 | } 41 | 42 | [Fact] 43 | public void ToPaginableTest() 44 | { 45 | using (var session = NhHelper.OpenSession()) 46 | { 47 | var list = session.QueryOver().ToPaginable(9); 48 | var page = list.GetPage(2); 49 | page.TotalPageCount.ShouldBe(24); 50 | page.TotalMemberCount.ShouldBe(210); 51 | page.CurrentPageNumber.ShouldBe(2); 52 | page.PageSize.ShouldBe(9); 53 | page.CurrentPageSize.ShouldBe(9); 54 | page.HasNext.ShouldBeTrue(); 55 | page.HasPrevious.ShouldBeTrue(); 56 | 57 | page[0].Value.Id.ShouldBe(10); 58 | page[1].Value.Id.ShouldBe(11); 59 | page[2].Value.Id.ShouldBe(12); 60 | page[3].Value.Id.ShouldBe(13); 61 | page[4].Value.Id.ShouldBe(14); 62 | page[5].Value.Id.ShouldBe(15); 63 | page[6].Value.Id.ShouldBe(16); 64 | page[7].Value.Id.ShouldBe(17); 65 | page[8].Value.Id.ShouldBe(18); 66 | } 67 | } 68 | 69 | [Fact] 70 | public void GetPageFromSessionTest() 71 | { 72 | using (var session = NhHelper.OpenSession()) 73 | { 74 | var page = session.GetPage(1, 9); 75 | page.TotalPageCount.ShouldBe(24); 76 | page.TotalMemberCount.ShouldBe(210); 77 | page.CurrentPageNumber.ShouldBe(1); 78 | page.PageSize.ShouldBe(9); 79 | page.CurrentPageSize.ShouldBe(9); 80 | page.HasNext.ShouldBeTrue(); 81 | page.HasPrevious.ShouldBeFalse(); 82 | 83 | page[0].Value.Id.ShouldBe(1); 84 | page[1].Value.Id.ShouldBe(2); 85 | page[2].Value.Id.ShouldBe(3); 86 | page[3].Value.Id.ShouldBe(4); 87 | page[4].Value.Id.ShouldBe(5); 88 | page[5].Value.Id.ShouldBe(6); 89 | page[6].Value.Id.ShouldBe(7); 90 | page[7].Value.Id.ShouldBe(8); 91 | page[8].Value.Id.ShouldBe(9); 92 | } 93 | } 94 | } 95 | 96 | public class Int32SampleNhMap : ClassMap 97 | { 98 | public Int32SampleNhMap() 99 | { 100 | base.Id(x => x.Id); 101 | base.Table("Int32Samples"); 102 | } 103 | } 104 | 105 | public static class NhHelper 106 | { 107 | private static ISessionFactory _sessionFactory; 108 | 109 | private static ISessionFactory SessionFactory { 110 | get { 111 | if (_sessionFactory == null) 112 | InitializeSessionFactory(); 113 | return _sessionFactory; 114 | } 115 | } 116 | 117 | private static void InitializeSessionFactory() 118 | { 119 | _sessionFactory = 120 | Fluently.Configure() 121 | .Database(MsSqlConfiguration.MsSql2012.ConnectionString(NhCoreTests.ConnectionString)) 122 | .Mappings(m => m.FluentMappings.Add()) 123 | .ExposeConfiguration(cfg => new SchemaExport(cfg).Create(true, false)) 124 | .BuildSessionFactory(); 125 | } 126 | 127 | public static ISession OpenSession() => SessionFactory.OpenSession(); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.SqlSugar/DotNetCore/Collections/Paginable/Extensions/SolidPageExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using DotNetCore.Collections.Paginable.Internal; 4 | using SqlSugar; 5 | 6 | // ReSharper disable once CheckNamespace 7 | namespace DotNetCore.Collections.Paginable 8 | { 9 | /// 10 | /// Extensions for solid page for SqlSugar 11 | /// 12 | public static class SolidPageExtensions 13 | { 14 | /// 15 | /// Make original SqlSugarQueryable result to SqlSugarPage collection. 16 | /// 17 | /// element type of your enumerable result 18 | /// SqlSugarQueryable 19 | /// limited member count 20 | /// 21 | public static PaginableSqlSugarQuery ToPaginable(this ISugarQueryable query, int? limitedMemberCount = null) 22 | => PaginableSqlSugarCollFactory.CreatePageSet(query, limitedMemberCount: limitedMemberCount); 23 | 24 | /// 25 | /// Make original SqlSugarQueryable result to SqlSugarPage collection. 26 | /// 27 | /// element type of your enumerable result 28 | /// SqlSugarQueryable 29 | /// page size 30 | /// limited member count 31 | /// 32 | public static PaginableSqlSugarQuery ToPaginable(this ISugarQueryable query, int pageSize, int? limitedMemberCount = null) 33 | => PaginableSqlSugarCollFactory.CreatePageSet(query, pageSize, limitedMemberCount); 34 | 35 | /// 36 | /// Get specific page from original SqlSugarQueryable source 37 | /// 38 | /// element type of your SqlSugarQueryable source 39 | /// original SqlSugarQueryable source 40 | /// page number 41 | /// 42 | public static IPage GetPage(this ISugarQueryable query, int pageNumber) 43 | => GetPage(query, pageNumber, PaginableSettingsManager.Settings.DefaultPageSize); 44 | 45 | /// 46 | /// Get specific page from original SqlSugarQueryable source 47 | /// 48 | /// element type of your SqlSugarQueryable source 49 | /// original SqlSugarQueryable source 50 | /// page number 51 | /// page size 52 | /// 53 | public static IPage GetPage(this ISugarQueryable query, int pageNumber, int pageSize) 54 | { 55 | if (query is null) 56 | throw new ArgumentNullException(nameof(query), $"{nameof(query)} can not be null."); 57 | 58 | if (pageNumber < 0) 59 | throw new IndexOutOfRangeException($"{nameof(pageNumber)} can not be less than zero"); 60 | 61 | if (pageSize < 0) 62 | throw new IndexOutOfRangeException($"{nameof(pageSize)} can not be less than zero"); 63 | 64 | return new SqlSugarPage(query, pageNumber, pageSize, SqlSugarHelper.Count(query)); 65 | } 66 | 67 | 68 | /// 69 | /// Get specific page from original SqlSugarQueryable source 70 | /// 71 | /// element type of your SqlSugarQueryable source 72 | /// original SqlSugarQueryable source 73 | /// page number 74 | /// 75 | public static Task> GetPageAsync(this ISugarQueryable query, int pageNumber) 76 | => GetPageAsync(query, pageNumber, PaginableSettingsManager.Settings.DefaultPageSize); 77 | 78 | /// 79 | /// Get specific page from original SqlSugarQueryable source 80 | /// 81 | /// element type of your SqlSugarQueryable source 82 | /// original SqlSugarQueryable source 83 | /// page number 84 | /// page size 85 | /// 86 | public static async Task> GetPageAsync(this ISugarQueryable query, int pageNumber, int pageSize) 87 | { 88 | if (query is null) 89 | throw new ArgumentNullException(nameof(query), $"{nameof(query)} can not be null."); 90 | 91 | if (pageNumber < 0) 92 | throw new IndexOutOfRangeException($"{nameof(pageNumber)} can not be less than zero"); 93 | 94 | if (pageSize < 0) 95 | throw new IndexOutOfRangeException($"{nameof(pageSize)} can not be less than zero"); 96 | 97 | return new SqlSugarPage(query, pageNumber, pageSize, (await SqlSugarHelper.CountAsync(query))); 98 | } 99 | } 100 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable/DotNetCore/Collections/Paginable/PaginableSetBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using DotNetCore.Collections.Paginable.Internal; 5 | 6 | namespace DotNetCore.Collections.Paginable 7 | { 8 | /// 9 | /// Abstract PaginableSet base 10 | /// 11 | /// 12 | public abstract class PaginableSetBase : IPaginable 13 | { 14 | /// 15 | /// Lazy pined paged cache. 16 | /// 17 | protected readonly Dictionary>> _lazyPinedPagesCache; 18 | 19 | /// 20 | /// Gets limited type 21 | /// 22 | protected LimitedMembersTypes _limitedType { get; } = LimitedMembersTypes.Unlimited; //as default, unlimited. 23 | 24 | private readonly int _limitedMemberCount; //magical number, as default, zero means unlimited. 25 | 26 | private readonly int _realMemberCount; 27 | //if LimitedType is customize mode, real_member_count equals to limited_member_count, otherwise, not. 28 | 29 | /// 30 | protected PaginableSetBase() { } 31 | 32 | /// 33 | protected PaginableSetBase(int pageSize, int realPageCount, int realMemberCount) 34 | { 35 | if (realMemberCount >= PaginableSettingsManager.Settings.MaxMemberItems) 36 | { 37 | throw new ArgumentOutOfRangeException(nameof(realMemberCount), "Paginable does not support large size result"); 38 | } 39 | 40 | PageSize = pageSize; 41 | PageCount = realPageCount; 42 | _lazyPinedPagesCache = new Dictionary>>(realPageCount); 43 | 44 | _realMemberCount = realMemberCount; 45 | _limitedMemberCount = 0; 46 | _limitedType = LimitedMembersTypes.Unlimited; 47 | } 48 | 49 | /// 50 | protected PaginableSetBase(int pageSize, int realPageCount, int realMemberCount, int limitedMembersCount) 51 | { 52 | PageSize = pageSize; 53 | PageCount = realPageCount; 54 | _lazyPinedPagesCache = new Dictionary>>(realPageCount); 55 | 56 | _realMemberCount = limitedMembersCount <= realMemberCount 57 | ? limitedMembersCount 58 | : realMemberCount; 59 | _limitedMemberCount = _realMemberCount; 60 | _limitedType = LimitedMembersTypes.Customize; 61 | } 62 | 63 | /// 64 | public IEnumerator> GetEnumerator() 65 | { 66 | for (int i = 1; i <= PageCount; i++) 67 | { 68 | if (HasInitializeSpecialPage(i, out var lazyPage)) 69 | { 70 | yield return lazyPage.Value; 71 | } 72 | else 73 | { 74 | var lazyValue = GetSpecifiedPage(i, PageSize, _realMemberCount); 75 | _lazyPinedPagesCache[i] = lazyValue; 76 | yield return lazyValue.Value; 77 | } 78 | } 79 | } 80 | 81 | IEnumerator IEnumerable.GetEnumerator() 82 | { 83 | return GetEnumerator(); 84 | } 85 | 86 | /// 87 | public int PageSize { get; } 88 | 89 | /// 90 | public int MemberCount => _realMemberCount; 91 | 92 | /// 93 | /// Gets limited member count 94 | /// 95 | public int LimitedMemberCount => _limitedMemberCount; 96 | 97 | /// 98 | /// Gets page count 99 | /// 100 | public int PageCount { get; } 101 | 102 | /// 103 | /// Get specific page from current PaginableSet 104 | /// 105 | /// 106 | /// 107 | public IPage GetPage(int pageNumber) 108 | { 109 | if (PageCount == 0) 110 | return new EmptyPage(); 111 | 112 | if (pageNumber < 1 || pageNumber > PageCount) 113 | throw new ArgumentOutOfRangeException(nameof(pageNumber), $"{nameof(pageNumber)} can not be less than 1 or greater than pages count."); 114 | 115 | if (HasInitializeSpecialPage(pageNumber, out var lazyPage)) 116 | return lazyPage.Value; 117 | 118 | var lazyValue = GetSpecifiedPage(pageNumber, PageSize, _realMemberCount); 119 | _lazyPinedPagesCache[pageNumber] = lazyValue; 120 | return lazyValue.Value; 121 | } 122 | 123 | private bool HasInitializeSpecialPage(int pageNumber, out Lazy> lazyPage) 124 | { 125 | if (pageNumber < 1 || pageNumber > PageCount) 126 | throw new ArgumentOutOfRangeException(nameof(pageNumber)); 127 | return _lazyPinedPagesCache.TryGetValue(pageNumber, out lazyPage); 128 | } 129 | 130 | /// 131 | /// Get specified page 132 | /// 133 | /// 134 | /// 135 | /// 136 | /// 137 | protected abstract Lazy> GetSpecifiedPage(int currentPageNumber, int pageSize, int realMemberCount); 138 | } 139 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Paginable.FreeSql/DotNetCore/Collections/Paginable/Extensions/SolidPageExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq.Expressions; 3 | using System.Threading.Tasks; 4 | using DotNetCore.Collections.Paginable.Internal; 5 | using FreeSql; 6 | 7 | // ReSharper disable once CheckNamespace 8 | namespace DotNetCore.Collections.Paginable 9 | { 10 | /// 11 | /// Extensions for solid page for FreeSql 12 | /// 13 | public static class SolidPageExtensions 14 | { 15 | /// 16 | /// Make original FreeSql.Select`1 result to FreeSqlPage collection. 17 | /// 18 | /// element type of your enumerable result 19 | /// FreeSql.Select`1 20 | /// limited member count 21 | /// include nested members 22 | /// 23 | public static PaginableFreeSqlQuery ToPaginable(this ISelect select, int? limitedMemberCount = null, bool? includeNestedMembers = null) where T : class 24 | => PaginableFreeSqlCollFactory.CreatePageSet(select, limitedMemberCount: limitedMemberCount, includeNestedMembers: includeNestedMembers); 25 | 26 | /// 27 | /// Make original FreeSql.Select`1 result to FreeSqlPage collection. 28 | /// 29 | /// element type of your enumerable result 30 | /// FreeSql.Select`1 31 | /// page size 32 | /// limited member count 33 | /// include nested members 34 | /// 35 | public static PaginableFreeSqlQuery ToPaginable(this ISelect select, int pageSize, int? limitedMemberCount = null, bool? includeNestedMembers = null) 36 | where T : class 37 | => PaginableFreeSqlCollFactory.CreatePageSet(select, pageSize, limitedMemberCount, includeNestedMembers); 38 | 39 | /// 40 | /// Get specific page from original FreeSql.Select`1 source 41 | /// 42 | /// element type of your FreeSql.Select`1 source 43 | /// original FreeSql.Select`1 source 44 | /// page number 45 | /// include nested members 46 | /// 47 | public static IPage GetPage(this ISelect select, int pageNumber, bool includeNestedMembers = false) where T : class 48 | => GetPage(select, pageNumber, PaginableSettingsManager.Settings.DefaultPageSize, includeNestedMembers); 49 | 50 | /// 51 | /// Get specific page from original FreeSql.Select`1 source 52 | /// 53 | /// element type of your FreeSql.Select`1 source 54 | /// original FreeSql.Select`1 source 55 | /// page number 56 | /// page size 57 | /// include nested members 58 | /// 59 | public static IPage GetPage(this ISelect select, int pageNumber, int pageSize, bool includeNestedMembers = false) where T : class 60 | { 61 | if (select is null) 62 | throw new ArgumentNullException(nameof(select), $"{nameof(select)} can not be null."); 63 | 64 | if (pageNumber < 0) 65 | throw new IndexOutOfRangeException($"{nameof(pageNumber)} can not be less than zero"); 66 | 67 | if (pageSize < 0) 68 | throw new IndexOutOfRangeException($"{nameof(pageSize)} can not be less than zero"); 69 | 70 | return new FreeSqlPage(select, pageNumber, pageSize, FreeSqlHelper.Count(select).AsInt32(), includeNestedMembers); 71 | } 72 | 73 | /// 74 | /// Get specific page from original FreeSql.Select`1 source 75 | /// 76 | /// element type of your FreeSql.Select`1 source 77 | /// original FreeSql.Select`1 source 78 | /// page number 79 | /// include nested members 80 | /// 81 | public static Task> GetPageAsync(this ISelect select, int pageNumber, bool includeNestedMembers = false) where T : class 82 | => GetPageAsync(select, pageNumber, PaginableSettingsManager.Settings.DefaultPageSize, includeNestedMembers); 83 | 84 | /// 85 | /// Get specific page from original FreeSql.Select`1 source 86 | /// 87 | /// element type of your FreeSql.Select`1 source 88 | /// original FreeSql.Select`1 source 89 | /// page number 90 | /// page size 91 | /// include nested members 92 | /// 93 | public static async Task> GetPageAsync(this ISelect select, int pageNumber, int pageSize, bool includeNestedMembers = false) where T : class 94 | { 95 | if (select is null) 96 | throw new ArgumentNullException(nameof(select), $"{nameof(select)} can not be null."); 97 | 98 | if (pageNumber < 0) 99 | throw new IndexOutOfRangeException($"{nameof(pageNumber)} can not be less than zero"); 100 | 101 | if (pageSize < 0) 102 | throw new IndexOutOfRangeException($"{nameof(pageSize)} can not be less than zero"); 103 | 104 | return new FreeSqlPage(select, pageNumber, pageSize, (await FreeSqlHelper.CountAsync(select)).AsInt32(), includeNestedMembers); 105 | } 106 | } 107 | } -------------------------------------------------------------------------------- /src/DotNetCore.Collections.Multi/MultiList.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace DotNetCore.Collections.Multi 6 | { 7 | public class MultiList 8 | { 9 | private readonly List _hashcodeList; 10 | private readonly Dictionary _entries; 11 | private readonly object _lockObj = new object(); 12 | 13 | public MultiList() 14 | { 15 | _hashcodeList = new List(); 16 | _entries = new Dictionary(); 17 | } 18 | 19 | public void Add(T element) 20 | { 21 | Add(element, 1); 22 | } 23 | 24 | public void Add(T element, int times) 25 | { 26 | var hashcode = GetValueHashCode(element); 27 | lock (_lockObj) 28 | { 29 | var safeTimes = FixTimes(times); 30 | if (_hashcodeList.Contains(hashcode)) 31 | { 32 | _entries[hashcode].Count += safeTimes; 33 | } 34 | else 35 | { 36 | _hashcodeList.Add(hashcode); 37 | _entries.Add(hashcode, new Entry(element, safeTimes)); 38 | } 39 | } 40 | } 41 | 42 | public bool Contains(T value) 43 | { 44 | var hashcode = GetValueHashCode(value); 45 | return _hashcodeList.Contains(hashcode); 46 | } 47 | 48 | public bool ContainsAll(IEnumerable elements) 49 | { 50 | if (elements == null) 51 | return false; 52 | foreach (var item in elements) 53 | if (!Contains(item)) 54 | return false; 55 | return true; 56 | } 57 | 58 | public int Count(T element) 59 | { 60 | var hashcode = GetValueHashCode(element); 61 | lock (_hashcodeList) 62 | { 63 | if (!_hashcodeList.Contains(hashcode)) 64 | return 0; 65 | return _entries[hashcode].Count; 66 | } 67 | } 68 | 69 | public int SetCount(T element, int times) 70 | { 71 | var hashcode = GetValueHashCode(element); 72 | var result = 0; 73 | lock (_lockObj) 74 | { 75 | var safeTimes = FixTimes(times); 76 | if (_hashcodeList.Contains(hashcode)) 77 | { 78 | if (safeTimes > 0) 79 | { 80 | var entry = _entries[hashcode]; 81 | entry.Count = safeTimes; 82 | } 83 | else 84 | { 85 | _hashcodeList.Remove(hashcode); 86 | _entries.Remove(hashcode); 87 | } 88 | } 89 | } 90 | 91 | return result; 92 | } 93 | 94 | public List ToList() 95 | { 96 | lock (_hashcodeList) 97 | { 98 | return _entries.Values.Select(x => x.Value).ToList(); 99 | } 100 | } 101 | 102 | public List EntrySet() 103 | { 104 | lock (_hashcodeList) 105 | { 106 | return _entries.Values.ToList(); 107 | } 108 | } 109 | 110 | public bool Remove(T element) 111 | { 112 | var hashcode = GetValueHashCode(element); 113 | lock (_hashcodeList) 114 | { 115 | if (_hashcodeList.Contains(hashcode)) 116 | { 117 | return _hashcodeList.Remove(hashcode) && _entries.Remove(hashcode); 118 | } 119 | } 120 | 121 | return true; 122 | } 123 | 124 | public int Remove(T element, int times) 125 | { 126 | var hashcode = GetValueHashCode(element); 127 | var result = 0; 128 | lock (_lockObj) 129 | { 130 | var safeTimes = FixTimes(times); 131 | if (_hashcodeList.Contains(hashcode)) 132 | { 133 | var entry = _entries[hashcode]; 134 | var temp = entry.Count - safeTimes; 135 | if (temp > 0) 136 | { 137 | entry.Count = temp; 138 | result = temp; 139 | } 140 | else 141 | { 142 | _hashcodeList.Remove(hashcode); 143 | _entries.Remove(hashcode); 144 | } 145 | } 146 | } 147 | 148 | return result; 149 | } 150 | 151 | public bool RemoveAll(IEnumerable collection) 152 | { 153 | if (collection == null) 154 | return true; 155 | var hashcodeList = collection.Select(GetValueHashCode).ToList(); 156 | lock (_lockObj) 157 | { 158 | foreach (var hashcode in hashcodeList) 159 | { 160 | if (_hashcodeList.Contains(hashcode)) 161 | { 162 | _hashcodeList.Remove(hashcode); 163 | _entries.Remove(hashcode); 164 | } 165 | } 166 | } 167 | 168 | return true; 169 | } 170 | 171 | public class Entry 172 | { 173 | public Entry(T value, int times = 1) 174 | { 175 | Value = value; 176 | Count = times; 177 | } 178 | 179 | public int Count { get; internal set; } 180 | 181 | public T Value { get; } 182 | } 183 | 184 | private int GetValueHashCode(T value) 185 | { 186 | return value == null ? 0 : value.GetHashCode(); 187 | } 188 | 189 | private int FixTimes(int uncheckedTimes) 190 | { 191 | return uncheckedTimes <= 0 ? 1 : uncheckedTimes; 192 | } 193 | 194 | public override string ToString() 195 | { 196 | return string.Join(",", ToList()); 197 | } 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio Code 28 | .vscode/ 29 | 30 | # Visual Studio 2015 cache/options directory 31 | .vs/ 32 | # Uncomment if you have tasks that create the project's static files in wwwroot 33 | #wwwroot/ 34 | 35 | # MSTest test Results 36 | [Tt]est[Rr]esult*/ 37 | [Bb]uild[Ll]og.* 38 | 39 | # NUNIT 40 | *.VisualState.xml 41 | TestResult.xml 42 | 43 | # Build Results of an ATL Project 44 | [Dd]ebugPS/ 45 | [Rr]eleasePS/ 46 | dlldata.c 47 | 48 | # .NET Core 49 | project.lock.json 50 | project.fragment.lock.json 51 | artifacts/ 52 | **/Properties/launchSettings.json 53 | 54 | *_i.c 55 | *_p.c 56 | *_i.h 57 | *.ilk 58 | *.meta 59 | *.obj 60 | *.pch 61 | *.pdb 62 | *.pgc 63 | *.pgd 64 | *.rsp 65 | *.sbr 66 | *.tlb 67 | *.tli 68 | *.tlh 69 | *.tmp 70 | *.tmp_proj 71 | *.log 72 | *.vspscc 73 | *.vssscc 74 | .builds 75 | *.pidb 76 | *.svclog 77 | *.scc 78 | 79 | # Chutzpah Test files 80 | _Chutzpah* 81 | 82 | # Visual C++ cache files 83 | ipch/ 84 | *.aps 85 | *.ncb 86 | *.opendb 87 | *.opensdf 88 | *.sdf 89 | *.cachefile 90 | *.VC.db 91 | *.VC.VC.opendb 92 | 93 | # Visual Studio profiler 94 | *.psess 95 | *.vsp 96 | *.vspx 97 | *.sap 98 | 99 | # TFS 2012 Local Workspace 100 | $tf/ 101 | 102 | # Guidance Automation Toolkit 103 | *.gpState 104 | 105 | # ReSharper is a .NET coding add-in 106 | _ReSharper*/ 107 | *.[Rr]e[Ss]harper 108 | *.DotSettings.user 109 | 110 | # JustCode is a .NET coding add-in 111 | .JustCode 112 | 113 | # TeamCity is a build add-in 114 | _TeamCity* 115 | 116 | # DotCover is a Code Coverage Tool 117 | *.dotCover 118 | 119 | # Visual Studio code coverage results 120 | *.coverage 121 | *.coveragexml 122 | 123 | # NCrunch 124 | _NCrunch_* 125 | .*crunch*.local.xml 126 | nCrunchTemp_* 127 | 128 | # MightyMoose 129 | *.mm.* 130 | AutoTest.Net/ 131 | 132 | # Web workbench (sass) 133 | .sass-cache/ 134 | 135 | # Installshield output folder 136 | [Ee]xpress/ 137 | 138 | # DocProject is a documentation generator add-in 139 | DocProject/buildhelp/ 140 | DocProject/Help/*.HxT 141 | DocProject/Help/*.HxC 142 | DocProject/Help/*.hhc 143 | DocProject/Help/*.hhk 144 | DocProject/Help/*.hhp 145 | DocProject/Help/Html2 146 | DocProject/Help/html 147 | 148 | # Click-Once directory 149 | publish/ 150 | 151 | # Publish Web Output 152 | *.[Pp]ublish.xml 153 | *.azurePubxml 154 | # TODO: Comment the next line if you want to checkin your web deploy settings 155 | # but database connection strings (with potential passwords) will be unencrypted 156 | *.pubxml 157 | *.publishproj 158 | 159 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 160 | # checkin your Azure Web App publish settings, but sensitive information contained 161 | # in these scripts will be unencrypted 162 | PublishScripts/ 163 | 164 | # NuGet Packages 165 | *.nupkg 166 | # The packages folder can be ignored because of Package Restore 167 | **/packages/* 168 | # except build/, which is used as an MSBuild target. 169 | !**/packages/build/ 170 | # Uncomment if necessary however generally it will be regenerated when needed 171 | #!**/packages/repositories.config 172 | # NuGet v3's project.json files produces more ignorable files 173 | *.nuget.props 174 | *.nuget.targets 175 | 176 | # Microsoft Azure Build Output 177 | csx/ 178 | *.build.csdef 179 | 180 | # Microsoft Azure Emulator 181 | ecf/ 182 | rcf/ 183 | 184 | # Windows Store app package directories and files 185 | AppPackages/ 186 | BundleArtifacts/ 187 | Package.StoreAssociation.xml 188 | _pkginfo.txt 189 | 190 | # Visual Studio cache files 191 | # files ending in .cache can be ignored 192 | *.[Cc]ache 193 | # but keep track of directories ending in .cache 194 | !*.[Cc]ache/ 195 | 196 | # Others 197 | ClientBin/ 198 | ~$* 199 | *~ 200 | *.dbmdl 201 | *.dbproj.schemaview 202 | *.jfm 203 | *.pfx 204 | *.publishsettings 205 | orleans.codegen.cs 206 | 207 | # Since there are multiple workflows, uncomment next line to ignore bower_components 208 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 209 | #bower_components/ 210 | 211 | # RIA/Silverlight projects 212 | Generated_Code/ 213 | 214 | # Backup & report files from converting an old project file 215 | # to a newer Visual Studio version. Backup files are not needed, 216 | # because we have git ;-) 217 | _UpgradeReport_Files/ 218 | Backup*/ 219 | UpgradeLog*.XML 220 | UpgradeLog*.htm 221 | 222 | # SQL Server files 223 | *.mdf 224 | *.ldf 225 | *.ndf 226 | 227 | # Business Intelligence projects 228 | *.rdl.data 229 | *.bim.layout 230 | *.bim_*.settings 231 | 232 | # Microsoft Fakes 233 | FakesAssemblies/ 234 | 235 | # GhostDoc plugin setting file 236 | *.GhostDoc.xml 237 | 238 | # Node.js Tools for Visual Studio 239 | .ntvs_analysis.dat 240 | node_modules/ 241 | 242 | # Typescript v1 declaration files 243 | typings/ 244 | 245 | # Visual Studio 6 build log 246 | *.plg 247 | 248 | # Visual Studio 6 workspace options file 249 | *.opt 250 | 251 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 252 | *.vbw 253 | 254 | # Visual Studio LightSwitch build output 255 | **/*.HTMLClient/GeneratedArtifacts 256 | **/*.DesktopClient/GeneratedArtifacts 257 | **/*.DesktopClient/ModelManifest.xml 258 | **/*.Server/GeneratedArtifacts 259 | **/*.Server/ModelManifest.xml 260 | _Pvt_Extensions 261 | 262 | # Paket dependency manager 263 | .paket/paket.exe 264 | paket-files/ 265 | 266 | # FAKE - F# Make 267 | .fake/ 268 | 269 | # JetBrains Rider 270 | .idea/ 271 | *.sln.iml 272 | 273 | # CodeRush 274 | .cr/ 275 | 276 | # Python Tools for Visual Studio (PTVS) 277 | __pycache__/ 278 | *.pyc 279 | 280 | # Cake - Uncomment if you are using it 281 | # tools/** 282 | # !tools/packages.config 283 | 284 | # Telerik's JustMock configuration file 285 | *.jmconfig 286 | 287 | # BizTalk build output 288 | *.btp.cs 289 | *.btm.cs 290 | *.odx.cs 291 | *.xsd.cs 292 | BenchmarkDotNet.Artifacts/ 293 | --------------------------------------------------------------------------------