diff --git a/src/DotNetToolkit.Repository/Queries/IQueryOptions.cs b/src/DotNetToolkit.Repository/Queries/IQueryOptions.cs
new file mode 100644
index 00000000..6e3f8604
--- /dev/null
+++ b/src/DotNetToolkit.Repository/Queries/IQueryOptions.cs
@@ -0,0 +1,18 @@
+namespace DotNetToolkit.Repository.Queries
+{
+ using System.Linq;
+
+ ///
+ /// Represents a query options which can be used for sorting or paging on queries.
+ ///
+ /// The entity type of the repository.
+ public interface IQueryOptions
+ {
+ ///
+ /// Applies the current options to the specified query.
+ ///
+ /// The query.
+ /// The new query with the defined options applied.
+ IQueryable Apply(IQueryable query);
+ }
+}
diff --git a/src/DotNetToolkit.Repository/Queries/PagingOptions.cs b/src/DotNetToolkit.Repository/Queries/PagingOptions.cs
new file mode 100644
index 00000000..110097a5
--- /dev/null
+++ b/src/DotNetToolkit.Repository/Queries/PagingOptions.cs
@@ -0,0 +1,113 @@
+namespace DotNetToolkit.Repository.Queries
+{
+ using System;
+ using System.Linq;
+ using System.Linq.Expressions;
+
+ ///
+ /// Represents a paging option.
+ ///
+ /// The entity type of the repository.
+ /// The type of the property that is being sorted.
+ public class PagingOptions : SortingOptions
+ {
+ #region Fields
+
+ private const int DefaultPageSize = 100;
+ private int _pageIndex;
+ private int _pageSize;
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// Gets or sets the number of rows of the data page to retrieve.
+ ///
+ public int PageSize
+ {
+ get { return _pageSize; }
+ set
+ {
+ if (value <= 0)
+ throw new ArgumentException($"{nameof(PageSize)} cannot be lower than zero.");
+
+ _pageSize = value;
+ }
+ }
+
+ ///
+ /// Gets or sets the zero-based index of the data page to retrieve.
+ ///
+ public int PageIndex
+ {
+ get { return _pageIndex; }
+ set
+ {
+ if (value < 1)
+ throw new ArgumentOutOfRangeException(nameof(PageIndex), "Cannot be lower than 1.");
+
+ _pageIndex = value;
+ }
+ }
+
+ ///
+ /// Gets the page count.
+ ///
+ public int PageCount { get; private set; }
+
+ #endregion
+
+ #region Constructors
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The zero-based index of the data page to retrieve.
+ /// The sorting expression.
+ /// if set to true use descending order; otherwise, use ascending.
+ public PagingOptions(int pageIndex, Expression> sorting, bool isDescending = false) : base(sorting, isDescending)
+ {
+ PageIndex = pageIndex;
+ PageSize = DefaultPageSize;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The zero-based index of the data page to retrieve.
+ /// The number of rows of the data page to retrieve.
+ /// The sorting expression.
+ /// if set to true use descending order; otherwise, use ascending.
+ public PagingOptions(int pageIndex, int pageSize, Expression> sorting, bool isDescending = false) : base(sorting, isDescending)
+ {
+ PageIndex = pageIndex;
+ PageSize = pageSize;
+ }
+
+ #endregion
+
+ #region Overrides of SortingOptions
+
+ ///
+ /// Applies the current options to the specified query.
+ ///
+ /// The query.
+ /// The new query with the defined options applied.
+ public override IQueryable Apply(IQueryable query)
+ {
+ var pageCount = (int)Math.Ceiling(query.Count() / (decimal)PageSize);
+
+ if (PageIndex > pageCount)
+ throw new ArgumentOutOfRangeException(nameof(PageIndex), "Cannot be greater than the total number of pages.");
+
+ PageCount = pageCount;
+
+ query = base.Apply(query);
+
+ return query.Skip((PageIndex - 1) * PageSize).Take(PageSize);
+ }
+
+ #endregion
+ }
+}
diff --git a/src/DotNetToolkit.Repository/Queries/SortingOptions.cs b/src/DotNetToolkit.Repository/Queries/SortingOptions.cs
new file mode 100644
index 00000000..dc0cc27c
--- /dev/null
+++ b/src/DotNetToolkit.Repository/Queries/SortingOptions.cs
@@ -0,0 +1,69 @@
+namespace DotNetToolkit.Repository.Queries
+{
+ using System;
+ using System.Linq;
+ using System.Linq.Expressions;
+
+ ///
+ /// Represents a sorting option.
+ ///
+ /// The entity type of the repository.
+ /// The type of the property that is being sorted.
+ public class SortingOptions : IQueryOptions
+ {
+ #region Fields
+
+ private readonly Expression> _sorting;
+
+ #endregion
+
+ #region Properties
+
+ ///
+ /// Gets or sets a value indicating whether this sorting option is descending.
+ ///
+ ///
+ /// true if this sorting option is descending; otherwise, false.
+ ///
+ public bool IsDescending { get; set; }
+
+ #endregion
+
+ #region Constructors
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The sorting expression.
+ /// if set to true use descending order; otherwise, use ascending.
+ public SortingOptions(Expression> sorting, bool isDescending = false)
+ {
+ _sorting = sorting;
+
+ IsDescending = isDescending;
+ }
+
+ #endregion
+
+ #region Implementation of IQueryOptions
+
+ ///
+ /// Applies the current options to the specified query.
+ ///
+ /// The query.
+ /// The new query with the defined options applied.
+ public virtual IQueryable Apply(IQueryable query)
+ {
+ if (_sorting != null)
+ {
+ query = IsDescending
+ ? query.OrderByDescending(_sorting)
+ : query.OrderBy(_sorting);
+ }
+
+ return query;
+ }
+
+ #endregion
+ }
+}
diff --git a/src/DotNetToolkit.Repository/RepositoryBase.cs b/src/DotNetToolkit.Repository/RepositoryBase.cs
index a98c5549..31b57f08 100644
--- a/src/DotNetToolkit.Repository/RepositoryBase.cs
+++ b/src/DotNetToolkit.Repository/RepositoryBase.cs
@@ -2,6 +2,7 @@
{
using FetchStrategies;
using Helpers;
+ using Queries;
using Specifications;
using System;
using System.Collections.Generic;
@@ -62,13 +63,13 @@ protected virtual IQueryable AsQueryable()
///
protected virtual TEntity GetQuery(TKey key, IFetchStrategy fetchStrategy)
{
- return (TEntity)GetQuery(ByPrimaryKeySpecification(key, fetchStrategy));
+ return GetQuery(ByPrimaryKeySpecification(key, fetchStrategy));
}
///
/// Gets an entity query with the given primary key value from the repository.
///
- protected virtual TEntity GetQuery(TKey key)
+ protected TEntity GetQuery(TKey key)
{
return Get(key, (IFetchStrategy)null);
}
@@ -76,23 +77,40 @@ protected virtual TEntity GetQuery(TKey key)
///
/// Gets an entity query that satisfies the criteria specified by the from the repository.
///
- protected virtual IQueryable GetQuery(ISpecification criteria)
+ protected TEntity GetQuery(ISpecification criteria)
+ {
+ var query = GetQuery(criteria.FetchStrategy);
+
+ return criteria.SatisfyingEntityFrom(query);
+ }
+
+ ///
+ /// Gets an entity query that satisfies the criteria specified by the from the repository.
+ ///
+ protected IQueryable GetQuery(ISpecification criteria, IQueryOptions options)
{
if (criteria == null)
throw new ArgumentNullException(nameof(criteria));
- return GetQuery(criteria.FetchStrategy);
+ var query = GetQuery(criteria.FetchStrategy);
+
+ query = criteria.SatisfyingEntitiesFrom(query);
+
+ if (options != null)
+ query = options.Apply(query);
+
+ return query;
}
///
/// Gets an entity query that satisfies the criteria specified by the from the repository.
///
- protected virtual IQueryable GetQuery(Expression> predicate)
+ protected IQueryable GetQuery(Expression> predicate, IQueryOptions options)
{
if (predicate == null)
throw new ArgumentNullException(nameof(predicate));
- return GetQuery(new Specification(predicate));
+ return GetQuery(new Specification(predicate), options);
}
///
@@ -134,7 +152,7 @@ protected virtual ISpecification ByPrimaryKeySpecification(TKey key, IF
/// The number of entities contained in the repository.
public int Count()
{
- return GetQuery().Count();
+ return Count((ISpecification)null);
}
///
@@ -144,7 +162,9 @@ public int Count()
/// The number of entities that satisfied the criteria specified by the in the repository.
public int Count(ISpecification criteria)
{
- return GetQuery(criteria).Count();
+ var predicate = criteria?.Predicate?.Compile();
+
+ return predicate == null ? GetQuery().Count() : GetQuery().Count(predicate);
}
///
@@ -154,7 +174,7 @@ public int Count(ISpecification criteria)
/// The number of entities that satisfied the criteria specified by the in the repository.
public int Count(Expression> predicate)
{
- return GetQuery(predicate == null ? null : new Specification(predicate)).Count();
+ return Count(predicate == null ? null : new Specification(predicate));
}
#endregion
@@ -390,26 +410,28 @@ public bool Exists(TKey key)
/// Finds the first entity in the repository that satisfies the criteria specified by the in the repository.
///
/// A function to filter each entity.
+ /// The options to apply to the query.
/// The entity that satisfied the criteria specified by the in the repository.
- public TEntity Find(Expression> predicate)
+ public TEntity Find(Expression> predicate, IQueryOptions options = null)
{
if (predicate == null)
throw new ArgumentNullException(nameof(predicate));
- return GetQuery(predicate).FirstOrDefault();
+ return GetQuery(predicate, options).FirstOrDefault();
}
///
/// Finds the first entity in the repository that satisfies the criteria specified by the in the repository.
///
/// The specification criteria that is used for matching entities against.
+ /// The options to apply to the query.
/// The entity that satisfied the criteria specified by the in the repository.
- public TEntity Find(ISpecification criteria)
+ public TEntity Find(ISpecification criteria, IQueryOptions options = null)
{
if (criteria == null)
throw new ArgumentNullException(nameof(criteria));
- return GetQuery(criteria).FirstOrDefault();
+ return GetQuery(criteria, options).FirstOrDefault();
}
///
@@ -417,8 +439,9 @@ public TEntity Find(ISpecification criteria)
///
/// A function to filter each entity.
/// A function to project each entity into a new form.
+ /// The options to apply to the query.
/// The projected entity result that satisfied the criteria specified by the in the repository.
- public TResult Find(Expression> predicate, Expression> selector)
+ public TResult Find(Expression> predicate, Expression> selector, IQueryOptions options = null)
{
if (predicate == null)
throw new ArgumentNullException(nameof(predicate));
@@ -426,7 +449,7 @@ public TResult Find(Expression> predicate, Expressi
if (selector == null)
throw new ArgumentNullException(nameof(selector));
- return GetQuery(predicate).Select(selector).FirstOrDefault();
+ return GetQuery(predicate, options).Select(selector).FirstOrDefault();
}
///
@@ -434,8 +457,9 @@ public TResult Find(Expression> predicate, Expressi
///
/// The specification criteria that is used for matching entities against.
/// A function to project each entity into a new form.
+ /// The options to apply to the query.
/// The projected entity result that satisfied the criteria specified by the in the repository.
- public TResult Find(ISpecification criteria, Expression> selector)
+ public TResult Find(ISpecification criteria, Expression> selector, IQueryOptions options = null)
{
if (criteria == null)
throw new ArgumentNullException(nameof(criteria));
@@ -443,33 +467,35 @@ public TResult Find(ISpecification criteria, Expression
/// Finds the collection of entities in the repository that satisfied the criteria specified by the .
///
/// A function to filter each entity.
+ /// The options to apply to the query.
/// The collection of entities in the repository that satisfied the criteria specified by the .
- public IEnumerable FindAll(Expression> predicate)
+ public IEnumerable FindAll(Expression> predicate, IQueryOptions options = null)
{
if (predicate == null)
throw new ArgumentNullException(nameof(predicate));
- return GetQuery(predicate).ToList();
+ return GetQuery(predicate, options).ToList();
}
///
/// Finds the collection of entities in the repository that satisfied the criteria specified by the .
///
/// The specification criteria that is used for matching entities against.
+ /// The options to apply to the query.
/// The collection of entities in the repository that satisfied the criteria specified by the .
- public IEnumerable FindAll(ISpecification criteria)
+ public IEnumerable FindAll(ISpecification criteria, IQueryOptions options = null)
{
if (criteria == null)
throw new ArgumentNullException(nameof(criteria));
- return GetQuery(criteria).ToList();
+ return GetQuery(criteria, options).ToList();
}
///
@@ -477,8 +503,9 @@ public IEnumerable FindAll(ISpecification criteria)
///
/// A function to filter each entity.
/// A function to project each entity into a new form.
+ /// The options to apply to the query.
/// The collection of projected entity results in the repository that satisfied the criteria specified by the .
- public IEnumerable FindAll(Expression> predicate, Expression> selector)
+ public IEnumerable FindAll(Expression> predicate, Expression> selector, IQueryOptions options = null)
{
if (predicate == null)
throw new ArgumentNullException(nameof(predicate));
@@ -486,7 +513,7 @@ public IEnumerable FindAll(Expression> pre
if (selector == null)
throw new ArgumentNullException(nameof(selector));
- return GetQuery(predicate).Select(selector).ToList();
+ return GetQuery(predicate, options).Select(selector).ToList();
}
///
@@ -494,8 +521,9 @@ public IEnumerable FindAll(Expression> pre
///
/// The specification criteria that is used for matching entities against.
/// A function to project each entity into a new form.
+ /// The options to apply to the query.
/// The collection of projected entity results in the repository that satisfied the criteria specified by the .
- public IEnumerable FindAll(ISpecification criteria, Expression> selector)
+ public IEnumerable FindAll(ISpecification criteria, Expression> selector, IQueryOptions options = null)
{
if (criteria == null)
throw new ArgumentNullException(nameof(criteria));
@@ -503,7 +531,7 @@ public IEnumerable FindAll(ISpecification criteria, E
if (selector == null)
throw new ArgumentNullException(nameof(selector));
- return GetQuery(criteria).Select(selector).ToList();
+ return GetQuery(criteria, options).Select(selector).ToList();
}
///
diff --git a/src/DotNetToolkit.Repository/Traits/ICanFind.cs b/src/DotNetToolkit.Repository/Traits/ICanFind.cs
index a2b4ebb0..72f1b1e2 100644
--- a/src/DotNetToolkit.Repository/Traits/ICanFind.cs
+++ b/src/DotNetToolkit.Repository/Traits/ICanFind.cs
@@ -1,5 +1,6 @@
namespace DotNetToolkit.Repository.Traits
{
+ using Queries;
using Specifications;
using System;
using System.Collections.Generic;
@@ -15,61 +16,69 @@ public interface ICanFind where TEntity : class
/// Finds the first entity in the repository that satisfies the criteria specified by the in the repository.
///
/// A function to filter each entity.
+ /// The options to apply to the query.
/// The entity that satisfied the criteria specified by the in the repository.
- TEntity Find(Expression> predicate);
+ TEntity Find(Expression> predicate, IQueryOptions options = null);
///
/// Finds the first entity in the repository that satisfies the criteria specified by the in the repository.
///
/// The specification criteria that is used for matching entities against.
+ /// The options to apply to the query.
/// The entity that satisfied the criteria specified by the in the repository.
- TEntity Find(ISpecification criteria);
+ TEntity Find(ISpecification criteria, IQueryOptions options = null);
///
/// Finds the first projected entity result in the repository that satisfies the criteria specified by the in the repository.
///
/// A function to filter each entity.
/// A function to project each entity into a new form.
+ /// The options to apply to the query.
/// The projected entity result that satisfied the criteria specified by the in the repository.
- TResult Find(Expression> predicate, Expression> selector);
+ TResult Find(Expression> predicate, Expression> selector, IQueryOptions options = null);
///
/// Finds the first projected entity result in the repository that satisfies the criteria specified by the in the repository.
///
/// The specification criteria that is used for matching entities against.
/// A function to project each entity into a new form.
+ /// The options to apply to the query.
/// The projected entity result that satisfied the criteria specified by the in the repository.
- TResult Find(ISpecification criteria, Expression> selector);
+ TResult Find(ISpecification criteria, Expression> selector, IQueryOptions options = null);
///
/// Finds the collection of entities in the repository that satisfied the criteria specified by the .
///
/// A function to filter each entity.
+ /// The options to apply to the query.
/// The collection of entities in the repository that satisfied the criteria specified by the .
- IEnumerable FindAll(Expression> predicate);
+ IEnumerable FindAll(Expression> predicate, IQueryOptions options = null);
///
/// Finds the collection of entities in the repository that satisfied the criteria specified by the .
///
/// The specification criteria that is used for matching entities against.
+ /// The options to apply to the query.
/// The collection of entities in the repository that satisfied the criteria specified by the .
- IEnumerable FindAll(ISpecification criteria);
+ IEnumerable FindAll(ISpecification criteria, IQueryOptions options = null);
///
/// Finds the collection of projected entity results in the repository that satisfied the criteria specified by the .
///
/// A function to filter each entity.
/// A function to project each entity into a new form.
+ /// The options to apply to the query.
/// The collection of projected entity results in the repository that satisfied the criteria specified by the .
- IEnumerable FindAll(Expression> predicate, Expression> selector);
+ IEnumerable FindAll(Expression> predicate, Expression> selector, IQueryOptions options = null);
///
/// Finds the collection of projected entity results in the repository that satisfied the criteria specified by the .
///
/// The specification criteria that is used for matching entities against.
/// A function to project each entity into a new form.
+ /// The options to apply to the query.
/// The collection of projected entity results in the repository that satisfied the criteria specified by the .
- IEnumerable FindAll(ISpecification criteria, Expression> selector);
+ IEnumerable FindAll(ISpecification criteria, Expression> selector, IQueryOptions options = null);
///
/// Determines whether the repository contains an entity that match the conditions defined by the specified by the .
diff --git a/test/DotNetToolkit.Repository.Integration.Test/EfRepositoryTests.cs b/test/DotNetToolkit.Repository.Integration.Test/EfRepositoryTests.cs
index 40e7b82d..d13199fc 100644
--- a/test/DotNetToolkit.Repository.Integration.Test/EfRepositoryTests.cs
+++ b/test/DotNetToolkit.Repository.Integration.Test/EfRepositoryTests.cs
@@ -2,8 +2,10 @@
{
using Data;
using EntityFramework;
+ using Queries;
using Specifications;
using System.Collections.Generic;
+ using System.Linq;
using Xunit;
public class EfRepositoryTests
@@ -177,6 +179,64 @@ public void Find()
}
}
+ [Fact]
+ public void Find_With_Sorting_Options_Ascending()
+ {
+ using (var context = TestDbContextFactory.Create())
+ {
+ var entities = new List
+ {
+ new Customer { Name = "Random Name 2" },
+ new Customer { Name = "Random Name 1" }
+ };
+
+ var spec = new Specification(x => x.Name.Contains("Random Name"));
+ var queryOptions = new SortingOptions(x => x.Name, true);
+ var repo = new EfRepository(context);
+
+ Assert.Null(repo.Find(x => x.Name.Contains("Random Name"), queryOptions)?.Name);
+ Assert.Null(repo.Find(spec, queryOptions)?.Name);
+ Assert.Null(repo.Find(x => x.Name.Contains("Random Name"), x => x.Name, queryOptions));
+ Assert.Null(repo.Find(spec, x => x.Name, queryOptions));
+
+ repo.Add(entities);
+
+ Assert.Equal("Random Name 2", repo.Find(x => x.Name.Contains("Random Name"), queryOptions).Name);
+ Assert.Equal("Random Name 2", repo.Find(spec, queryOptions).Name);
+ Assert.Equal("Random Name 2", repo.Find(x => x.Name.Contains("Random Name"), x => x.Name, queryOptions));
+ Assert.Equal("Random Name 2", repo.Find(spec, x => x.Name, queryOptions));
+ }
+ }
+
+ [Fact]
+ public void Find_With_Sorting_Options_Descending()
+ {
+ using (var context = TestDbContextFactory.Create())
+ {
+ var entities = new List
+ {
+ new Customer { Name = "Random Name 2" },
+ new Customer { Name = "Random Name 1" }
+ };
+
+ var spec = new Specification(x => x.Name.Contains("Random Name"));
+ var queryOptions = new SortingOptions(x => x.Name);
+ var repo = new EfRepository(context);
+
+ Assert.Null(repo.Find(x => x.Name.Contains("Random Name"), queryOptions)?.Name);
+ Assert.Null(repo.Find(spec, queryOptions)?.Name);
+ Assert.Null(repo.Find(x => x.Name.Contains("Random Name"), x => x.Name, queryOptions));
+ Assert.Null(repo.Find(spec, x => x.Name, queryOptions));
+
+ repo.Add(entities);
+
+ Assert.Equal("Random Name 1", repo.Find(x => x.Name.Contains("Random Name"), queryOptions).Name);
+ Assert.Equal("Random Name 1", repo.Find(spec, queryOptions).Name);
+ Assert.Equal("Random Name 1", repo.Find(x => x.Name.Contains("Random Name"), x => x.Name, queryOptions));
+ Assert.Equal("Random Name 1", repo.Find(spec, x => x.Name, queryOptions));
+ }
+ }
+
[Fact]
public void FindAll()
{
@@ -202,6 +262,200 @@ public void FindAll()
}
}
+ [Fact]
+ public void FindAll_With_Sorting_Options_Ascending()
+ {
+ using (var context = TestDbContextFactory.Create())
+ {
+ var entities = new List
+ {
+ new Customer { Name = "Random Name 2" },
+ new Customer { Name = "Random Name 1" }
+ };
+
+ var spec = new Specification(x => x.Name.Contains("Random Name"));
+ var queryOptions = new SortingOptions(x => x.Name, true);
+ var repo = new EfRepository(context);
+
+ Assert.Null(repo.FindAll(x => x.Name.Contains("Random Name"), queryOptions).FirstOrDefault()?.Name);
+ Assert.Null(repo.FindAll(spec, queryOptions).FirstOrDefault()?.Name);
+ Assert.Null(repo.FindAll(x => x.Name.Contains("Random Name"), x => x.Name, queryOptions).FirstOrDefault());
+ Assert.Null(repo.FindAll(spec, x => x.Name, queryOptions).FirstOrDefault());
+
+ repo.Add(entities);
+
+ Assert.Equal("Random Name 2", repo.FindAll(x => x.Name.Contains("Random Name"), queryOptions).First().Name);
+ Assert.Equal("Random Name 2", repo.FindAll(spec, queryOptions).First().Name);
+ Assert.Equal("Random Name 2", repo.FindAll(x => x.Name.Contains("Random Name"), x => x.Name, queryOptions).First());
+ Assert.Equal("Random Name 2", repo.FindAll(spec, x => x.Name, queryOptions).First());
+ }
+ }
+
+ [Fact]
+ public void FindAll_With_Sorting_Options_Descending()
+ {
+ using (var context = TestDbContextFactory.Create())
+ {
+ var entities = new List
+ {
+ new Customer { Name = "Random Name 2" },
+ new Customer { Name = "Random Name 1" }
+ };
+
+ var spec = new Specification(x => x.Name.Contains("Random Name"));
+ var queryOptions = new SortingOptions(x => x.Name);
+ var repo = new EfRepository(context);
+
+ Assert.Null(repo.FindAll(x => x.Name.Contains("Random Name"), queryOptions).FirstOrDefault()?.Name);
+ Assert.Null(repo.FindAll(spec, queryOptions).FirstOrDefault()?.Name);
+ Assert.Null(repo.FindAll(x => x.Name.Contains("Random Name"), x => x.Name, queryOptions).FirstOrDefault());
+ Assert.Null(repo.FindAll(spec, x => x.Name, queryOptions).FirstOrDefault());
+
+ repo.Add(entities);
+
+ Assert.Equal("Random Name 1", repo.FindAll(x => x.Name.Contains("Random Name"), queryOptions).First().Name);
+ Assert.Equal("Random Name 1", repo.FindAll(spec, queryOptions).First().Name);
+ Assert.Equal("Random Name 1", repo.FindAll(x => x.Name.Contains("Random Name"), x => x.Name, queryOptions).First());
+ Assert.Equal("Random Name 1", repo.FindAll(spec, x => x.Name, queryOptions).First());
+ }
+ }
+
+ [Fact]
+ public void FindAll_With_Paging_Options_Sort_Ascending()
+ {
+ using (var context = TestDbContextFactory.Create())
+ {
+ var entities = new List();
+
+ for (var i = 0; i < 21; i++)
+ {
+ entities.Add(new Customer { Name = "Random Name " + i });
+ }
+
+ var repo = new EfRepository(context);
+
+ repo.Add(entities);
+
+ var queryOptions = new PagingOptions(1, 5, x => x.Id);
+ var entitiesInDb = repo.FindAll(x => x.Name.Contains("Random Name"), queryOptions);
+
+ Assert.Equal(5, entitiesInDb.Count());
+ Assert.Equal("Random Name 0", entitiesInDb.ElementAt(0).Name);
+ Assert.Equal("Random Name 1", entitiesInDb.ElementAt(1).Name);
+ Assert.Equal("Random Name 2", entitiesInDb.ElementAt(2).Name);
+ Assert.Equal("Random Name 3", entitiesInDb.ElementAt(3).Name);
+ Assert.Equal("Random Name 4", entitiesInDb.ElementAt(4).Name);
+
+ queryOptions.PageIndex = 2;
+
+ entitiesInDb = repo.FindAll(x => x.Name.Contains("Random Name"), queryOptions);
+
+ Assert.Equal(5, entitiesInDb.Count());
+ Assert.Equal("Random Name 5", entitiesInDb.ElementAt(0).Name);
+ Assert.Equal("Random Name 6", entitiesInDb.ElementAt(1).Name);
+ Assert.Equal("Random Name 7", entitiesInDb.ElementAt(2).Name);
+ Assert.Equal("Random Name 8", entitiesInDb.ElementAt(3).Name);
+ Assert.Equal("Random Name 9", entitiesInDb.ElementAt(4).Name);
+
+ queryOptions.PageIndex = 3;
+
+ entitiesInDb = repo.FindAll(x => x.Name.Contains("Random Name"), queryOptions);
+
+ Assert.Equal(5, entitiesInDb.Count());
+ Assert.Equal("Random Name 10", entitiesInDb.ElementAt(0).Name);
+ Assert.Equal("Random Name 11", entitiesInDb.ElementAt(1).Name);
+ Assert.Equal("Random Name 12", entitiesInDb.ElementAt(2).Name);
+ Assert.Equal("Random Name 13", entitiesInDb.ElementAt(3).Name);
+ Assert.Equal("Random Name 14", entitiesInDb.ElementAt(4).Name);
+
+ queryOptions.PageIndex = 4;
+
+ entitiesInDb = repo.FindAll(x => x.Name.Contains("Random Name"), queryOptions);
+
+ Assert.Equal(5, entitiesInDb.Count());
+ Assert.Equal("Random Name 15", entitiesInDb.ElementAt(0).Name);
+ Assert.Equal("Random Name 16", entitiesInDb.ElementAt(1).Name);
+ Assert.Equal("Random Name 17", entitiesInDb.ElementAt(2).Name);
+ Assert.Equal("Random Name 18", entitiesInDb.ElementAt(3).Name);
+ Assert.Equal("Random Name 19", entitiesInDb.ElementAt(4).Name);
+
+ queryOptions.PageIndex = 5;
+
+ entitiesInDb = repo.FindAll(x => x.Name.Contains("Random Name"), queryOptions);
+
+ Assert.Single(entitiesInDb);
+ Assert.Equal("Random Name 20", entitiesInDb.ElementAt(0).Name);
+ }
+ }
+
+ [Fact]
+ public void FindAll_With_Paging_Options_Sort_Descending()
+ {
+ using (var context = TestDbContextFactory.Create())
+ {
+ var entities = new List();
+
+ for (var i = 0; i < 21; i++)
+ {
+ entities.Add(new Customer { Name = "Random Name " + i });
+ }
+
+ var repo = new EfRepository(context);
+
+ repo.Add(entities);
+
+ var queryOptions = new PagingOptions(1, 5, x => x.Id, true);
+ var entitiesInDb = repo.FindAll(x => x.Name.Contains("Random Name"), queryOptions);
+
+ Assert.Equal(5, entitiesInDb.Count());
+ Assert.Equal("Random Name 20", entitiesInDb.ElementAt(0).Name);
+ Assert.Equal("Random Name 19", entitiesInDb.ElementAt(1).Name);
+ Assert.Equal("Random Name 18", entitiesInDb.ElementAt(2).Name);
+ Assert.Equal("Random Name 17", entitiesInDb.ElementAt(3).Name);
+ Assert.Equal("Random Name 16", entitiesInDb.ElementAt(4).Name);
+
+ queryOptions.PageIndex = 2;
+
+ entitiesInDb = repo.FindAll(x => x.Name.Contains("Random Name"), queryOptions);
+
+ Assert.Equal(5, entitiesInDb.Count());
+ Assert.Equal("Random Name 15", entitiesInDb.ElementAt(0).Name);
+ Assert.Equal("Random Name 14", entitiesInDb.ElementAt(1).Name);
+ Assert.Equal("Random Name 13", entitiesInDb.ElementAt(2).Name);
+ Assert.Equal("Random Name 12", entitiesInDb.ElementAt(3).Name);
+ Assert.Equal("Random Name 11", entitiesInDb.ElementAt(4).Name);
+
+ queryOptions.PageIndex = 3;
+
+ entitiesInDb = repo.FindAll(x => x.Name.Contains("Random Name"), queryOptions);
+
+ Assert.Equal(5, entitiesInDb.Count());
+ Assert.Equal("Random Name 10", entitiesInDb.ElementAt(0).Name);
+ Assert.Equal("Random Name 9", entitiesInDb.ElementAt(1).Name);
+ Assert.Equal("Random Name 8", entitiesInDb.ElementAt(2).Name);
+ Assert.Equal("Random Name 7", entitiesInDb.ElementAt(3).Name);
+ Assert.Equal("Random Name 6", entitiesInDb.ElementAt(4).Name);
+
+ queryOptions.PageIndex = 4;
+
+ entitiesInDb = repo.FindAll(x => x.Name.Contains("Random Name"), queryOptions);
+
+ Assert.Equal(5, entitiesInDb.Count());
+ Assert.Equal("Random Name 5", entitiesInDb.ElementAt(0).Name);
+ Assert.Equal("Random Name 4", entitiesInDb.ElementAt(1).Name);
+ Assert.Equal("Random Name 3", entitiesInDb.ElementAt(2).Name);
+ Assert.Equal("Random Name 2", entitiesInDb.ElementAt(3).Name);
+ Assert.Equal("Random Name 1", entitiesInDb.ElementAt(4).Name);
+
+ queryOptions.PageIndex = 5;
+
+ entitiesInDb = repo.FindAll(x => x.Name.Contains("Random Name"), queryOptions);
+
+ Assert.Single(entitiesInDb);
+ Assert.Equal("Random Name 0", entitiesInDb.ElementAt(0).Name);
+ }
+ }
+
[Fact]
public void Get()
{
diff --git a/test/DotNetToolkit.Repository.Test/PagingOptionsTests.cs b/test/DotNetToolkit.Repository.Test/PagingOptionsTests.cs
new file mode 100644
index 00000000..b274d2c9
--- /dev/null
+++ b/test/DotNetToolkit.Repository.Test/PagingOptionsTests.cs
@@ -0,0 +1,133 @@
+namespace DotNetToolkit.Repository.Test
+{
+ using Data;
+ using Queries;
+ using System.Collections.Generic;
+ using System.Linq;
+ using Xunit;
+
+ public class PagingOptionsTests
+ {
+ [Fact]
+ public void Page_With_Sort__Ascending()
+ {
+ var entities = new List();
+
+ for (var i = 0; i < 21; i++)
+ {
+ entities.Add(new Customer { Id = i, Name = "Random Name " + i });
+ }
+
+ var queryOptions = new PagingOptions(1, 5, x => x.Id);
+ var queryable = queryOptions.Apply(entities.AsQueryable());
+
+ Assert.Equal(5, queryable.Count());
+ Assert.Equal("Random Name 0", queryable.ElementAt(0).Name);
+ Assert.Equal("Random Name 1", queryable.ElementAt(1).Name);
+ Assert.Equal("Random Name 2", queryable.ElementAt(2).Name);
+ Assert.Equal("Random Name 3", queryable.ElementAt(3).Name);
+ Assert.Equal("Random Name 4", queryable.ElementAt(4).Name);
+
+ queryOptions.PageIndex = 2;
+
+ queryable = queryOptions.Apply(entities.AsQueryable());
+
+ Assert.Equal(5, queryable.Count());
+ Assert.Equal("Random Name 5", queryable.ElementAt(0).Name);
+ Assert.Equal("Random Name 6", queryable.ElementAt(1).Name);
+ Assert.Equal("Random Name 7", queryable.ElementAt(2).Name);
+ Assert.Equal("Random Name 8", queryable.ElementAt(3).Name);
+ Assert.Equal("Random Name 9", queryable.ElementAt(4).Name);
+
+ queryOptions.PageIndex = 3;
+
+ queryable = queryOptions.Apply(entities.AsQueryable());
+
+ Assert.Equal(5, queryable.Count());
+ Assert.Equal("Random Name 10", queryable.ElementAt(0).Name);
+ Assert.Equal("Random Name 11", queryable.ElementAt(1).Name);
+ Assert.Equal("Random Name 12", queryable.ElementAt(2).Name);
+ Assert.Equal("Random Name 13", queryable.ElementAt(3).Name);
+ Assert.Equal("Random Name 14", queryable.ElementAt(4).Name);
+
+ queryOptions.PageIndex = 4;
+
+ queryable = queryOptions.Apply(entities.AsQueryable());
+
+ Assert.Equal(5, queryable.Count());
+ Assert.Equal("Random Name 15", queryable.ElementAt(0).Name);
+ Assert.Equal("Random Name 16", queryable.ElementAt(1).Name);
+ Assert.Equal("Random Name 17", queryable.ElementAt(2).Name);
+ Assert.Equal("Random Name 18", queryable.ElementAt(3).Name);
+ Assert.Equal("Random Name 19", queryable.ElementAt(4).Name);
+
+ queryOptions.PageIndex = 5;
+
+ queryable = queryOptions.Apply(entities.AsQueryable());
+
+ Assert.Single(queryable);
+ Assert.Equal("Random Name 20", queryable.ElementAt(0).Name);
+ }
+
+ [Fact]
+ public void Page_With_Sort_Descending()
+ {
+ var entities = new List();
+
+ for (var i = 0; i < 21; i++)
+ {
+ entities.Add(new Customer { Id = i, Name = "Random Name " + i });
+ }
+
+ var queryOptions = new PagingOptions(1, 5, x => x.Id, true);
+ var queryable = queryOptions.Apply(entities.AsQueryable());
+
+ Assert.Equal(5, queryable.Count());
+ Assert.Equal("Random Name 20", queryable.ElementAt(0).Name);
+ Assert.Equal("Random Name 19", queryable.ElementAt(1).Name);
+ Assert.Equal("Random Name 18", queryable.ElementAt(2).Name);
+ Assert.Equal("Random Name 17", queryable.ElementAt(3).Name);
+ Assert.Equal("Random Name 16", queryable.ElementAt(4).Name);
+
+ queryOptions.PageIndex = 2;
+
+ queryable = queryOptions.Apply(entities.AsQueryable());
+
+ Assert.Equal(5, queryable.Count());
+ Assert.Equal("Random Name 15", queryable.ElementAt(0).Name);
+ Assert.Equal("Random Name 14", queryable.ElementAt(1).Name);
+ Assert.Equal("Random Name 13", queryable.ElementAt(2).Name);
+ Assert.Equal("Random Name 12", queryable.ElementAt(3).Name);
+ Assert.Equal("Random Name 11", queryable.ElementAt(4).Name);
+
+ queryOptions.PageIndex = 3;
+
+ queryable = queryOptions.Apply(entities.AsQueryable());
+
+ Assert.Equal(5, queryable.Count());
+ Assert.Equal("Random Name 10", queryable.ElementAt(0).Name);
+ Assert.Equal("Random Name 9", queryable.ElementAt(1).Name);
+ Assert.Equal("Random Name 8", queryable.ElementAt(2).Name);
+ Assert.Equal("Random Name 7", queryable.ElementAt(3).Name);
+ Assert.Equal("Random Name 6", queryable.ElementAt(4).Name);
+
+ queryOptions.PageIndex = 4;
+
+ queryable = queryOptions.Apply(entities.AsQueryable());
+
+ Assert.Equal(5, queryable.Count());
+ Assert.Equal("Random Name 5", queryable.ElementAt(0).Name);
+ Assert.Equal("Random Name 4", queryable.ElementAt(1).Name);
+ Assert.Equal("Random Name 3", queryable.ElementAt(2).Name);
+ Assert.Equal("Random Name 2", queryable.ElementAt(3).Name);
+ Assert.Equal("Random Name 1", queryable.ElementAt(4).Name);
+
+ queryOptions.PageIndex = 5;
+
+ queryable = queryOptions.Apply(entities.AsQueryable());
+
+ Assert.Single(queryable);
+ Assert.Equal("Random Name 0", queryable.ElementAt(0).Name);
+ }
+ }
+}
diff --git a/test/DotNetToolkit.Repository.Test/SortingOptionsTests.cs b/test/DotNetToolkit.Repository.Test/SortingOptionsTests.cs
new file mode 100644
index 00000000..5f6f826c
--- /dev/null
+++ b/test/DotNetToolkit.Repository.Test/SortingOptionsTests.cs
@@ -0,0 +1,45 @@
+namespace DotNetToolkit.Repository.Test
+{
+ using Data;
+ using Queries;
+ using System.Collections.Generic;
+ using System.Linq;
+ using Xunit;
+
+ public class SortingOptionsTests
+ {
+ [Fact]
+ public void Descending_Sort()
+ {
+ var entities = new List();
+ for (var i = 10; i >= 1; i--)
+ {
+ entities.Add(new Customer { Name = "Random Name " + i });
+ }
+
+ var sortingOptions = new SortingOptions(x => x.Name);
+ var queryable = sortingOptions.Apply(entities.AsQueryable());
+
+ Assert.Equal("Random Name 1", queryable.First().Name);
+
+ Assert.Equal(10, queryable.Count());
+ }
+
+ [Fact]
+ public void Ascending_Sort()
+ {
+ var entities = new List();
+ for (var i = 10; i >= 1; i--)
+ {
+ entities.Add(new Customer { Name = "Random Name " + i });
+ }
+
+ var sortingOptions = new SortingOptions(x => x.Name, true);
+ var queryable = sortingOptions.Apply(entities.AsQueryable());
+
+ Assert.Equal("Random Name 9", queryable.First().Name);
+
+ Assert.Equal(10, queryable.Count());
+ }
+ }
+}