using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using xCommons.Extensions;
using xDataService.Constants;
using xExceptions.Constants;
using xModels.Base;
namespace xDataService.Extensions {
public static class IQueryableExtensions {
///
/// Apply Search Filter on a Query
///
///
///
///
///
public static IQueryable ApplyFilter (
this IQueryable source,
string filter
)
where T : XBaseEntity {
//
// Apply Filter ...
return source.Where (r => r.PropValuesContains (filter));
}
///
/// Apply Search Filter on a Query
///
///
///
///
///
public static async Task> ApplyFilterAsync (
this IQueryable source,
string filter
)
where T : XBaseEntity {
//
// Where Clause ...
Expression> whereClause = r => r
.PropValuesContains (filter);
//
// Generate Where Function ...
var whereFunc = whereClause.Compile ();
//
// Get Enumerable ...
var enumerator = source
.AsAsyncEnumerable ();
//
var result = new List ();
await
foreach (var entity in enumerator) {
//
var isApproved = whereFunc (entity);
if (isApproved) {
result.Add (entity);
}
}
//
return result.AsQueryable ();
}
///
/// Apply Search Filter on a Enumerable
///
///
///
///
///
public static async Task> ApplyFilterAsync (
this IEnumerable source,
string filter
)
where T : XBaseEntity {
//
// Where Clause ...
Expression> whereClause = r => r
.PropValuesContains (filter);
//
// Generate Where Function ...
var whereFunc = whereClause.Compile ();
//
// Get Enumerable ...
var enumerator = source
.AsQueryable ()
.AsAsyncEnumerable ();
//
var result = new List ();
await
foreach (var entity in enumerator) {
//
var isApproved = whereFunc (entity);
if (isApproved) {
result.Add (entity);
}
}
//
return result
.AsEnumerable ();
}
///
/// Apply Search Filter on a Enumerable
///
///
///
///
///
public static IEnumerable ApplyFilter (
this IEnumerable source,
string filter
)
where T : class {
//
// Apply Filter ...
return source.Where (r => r.PropValuesContains (filter));
}
///
/// provide a way to Order an IQueryable by string FieldName ...
///
///
///
///
///
public static IOrderedQueryable OrderBy (
this IQueryable query,
string propertyName
) {
//
var entityType = typeof (TSource);
//
// Create x => x.PropName
var propertyInfo = entityType.GetProperty (propertyName);
if (propertyInfo.IsNull ()) {
XException.InvalidArgs.Throw ();
}
//
ParameterExpression arg = Expression.Parameter (entityType, "x");
MemberExpression property = Expression.Property (arg, propertyName);
var selector = Expression.Lambda (property, new ParameterExpression[] { arg });
//
// Get System.Linq.Queryable.OrderBy() method.
var enumarableType = typeof (System.Linq.Queryable);
var method = enumarableType.GetMethods ()
.Where (m => m.Name == "OrderBy" && m.IsGenericMethodDefinition)
.Where (m => {
//
var parameters = m.GetParameters ().ToList ();
//
// Put more restriction here to ensure selecting the right overload
return parameters.Count == 2; // overload that has 2 parameters
}).Single ();
//
// The linq's OrderBy has two generic types, which provided here ...
MethodInfo genericMethod = method
.MakeGenericMethod (entityType, propertyInfo.PropertyType);
/*
Call query.OrderBy(selector), with query and selector: x=> x.PropName
Note that we pass the selector as Expression to the method and we don't compile it.
By doing so EF can extract "order by" columns and generate SQL for it.
*/
var newQuery = (IOrderedQueryable) genericMethod
.Invoke (genericMethod, new object[] { query, selector });
//
return newQuery;
}
///
/// provide a way to Order an IEnumerable by string FieldName ...
///
///
///
///
///
public static IOrderedEnumerable OrderBy (
this IEnumerable query,
string propertyName
) {
//
var entityType = typeof (TSource);
var propertyInfo = entityType.GetProperty (propertyName);
if (propertyInfo.IsNull ()) {
XException.InvalidArgs.Throw ();
}
//
return query.OrderBy (x => propertyInfo.GetValue (x, null));
}
///
/// provide a way to Order an IQueryable by string FieldName ...
///
///
///
///
///
public static IOrderedQueryable OrderByDescending (
this IQueryable query,
string propertyName
) {
//
var entityType = typeof (TSource);
//
// Create x => x.PropName
var propertyInfo = entityType.GetProperty (propertyName);
if (propertyInfo.IsNull ()) {
XException.InvalidArgs.Throw ();
}
//
ParameterExpression arg = Expression.Parameter (entityType, "x");
MemberExpression property = Expression.Property (arg, propertyName);
var selector = Expression.Lambda (property, new ParameterExpression[] { arg });
//
// Get System.Linq.Queryable.OrderBy() method.
var enumarableType = typeof (System.Linq.Queryable);
var method = enumarableType.GetMethods ()
.Where (m => m.Name == "OrderByDescending" && m.IsGenericMethodDefinition)
.Where (m => {
//
var parameters = m.GetParameters ().ToList ();
//
// Put more restriction here to ensure selecting the right overload
return parameters.Count == 2; // overload that has 2 parameters
}).Single ();
//
// The linq's OrderBy has two generic types, which provided here ...
MethodInfo genericMethod = method
.MakeGenericMethod (entityType, propertyInfo.PropertyType);
/*
Call query.OrderBy(selector), with query and selector: x=> x.PropName
Note that we pass the selector as Expression to the method and we don't compile it.
By doing so EF can extract "order by" columns and generate SQL for it.
*/
var newQuery = (IOrderedQueryable) genericMethod
.Invoke (genericMethod, new object[] { query, selector });
//
return newQuery;
}
///
/// provide a way to Order an IEnumerable by string FieldName ...
///
///
///
///
///
public static IOrderedEnumerable OrderByDescending (
this IEnumerable query,
string propertyName
) {
//
var entityType = typeof (TSource);
var propertyInfo = entityType.GetProperty (propertyName);
if (propertyInfo.IsNull ()) {
XException.InvalidArgs.Throw ();
}
//
return query.OrderByDescending (x => propertyInfo.GetValue (x, null));
}
///
/// Apply Sorting on a query
///
///
///
///
///
///
///
public static IQueryable ApplySorting (
this IQueryable source,
string sortBy,
bool isAscending,
IDictionary>> columnsMap = null
)
where T : XBaseEntity {
//
if (columnsMap == null) {
//
columnsMap = source.FirstOrDefault ()
.GetDefaultColumnsMap ();
//
if (columnsMap == null) {
return source;
}
}
//
// Validate SortBy ...
var sortByItem = columnsMap.Keys
.FirstOrDefault (p =>
p.ToNormalString () == sortBy.ToNormalString ());
if (sortByItem.IsNullOrEmpty ()) {
return source;
}
//
// Apply Sorting ...
if (isAscending) {
return source.OrderBy (sortByItem);
} else {
return source.OrderByDescending (sortByItem);
}
}
///
/// Apply Sorting on a query
///
///
///
///
///
///
///
public static IEnumerable ApplySorting (
this IEnumerable source,
string sortBy,
bool isAscending,
IDictionary>> columnsMap = null
)
where T : XBaseEntity {
//
if (columnsMap == null) {
//
columnsMap = source.FirstOrDefault ()
.GetDefaultColumnsMap ();
//
if (columnsMap == null) {
return source;
}
}
//
// Validate SortBy ...
var sortByItem = columnsMap.Keys
.FirstOrDefault (p =>
p.ToNormalString () == sortBy.ToNormalString ());
if (sortByItem.IsNullOrEmpty ()) {
return source;
}
//
// Apply Sorting ...
if (isAscending) {
return source.OrderBy (sortByItem);
} else {
return source.OrderByDescending (sortByItem);
}
}
///
/// Apply Sorting on a Enumerable
///
///
///
///
///
///
///
public static IEnumerable ApplySorting (
this IEnumerable source,
string sortBy,
bool isAscending,
IDictionary>> columnsMap = null
)
where T : class {
//
if (columnsMap == null) {
//
columnsMap = source.FirstOrDefault ()
.GetDefaultColumnsMap ();
//
if (columnsMap == null) {
return source;
}
}
//
// Validate SortBy ...
var sortByItem = columnsMap.Keys
.FirstOrDefault (p =>
p.ToNormalString () == sortBy.ToNormalString ());
if (sortByItem.IsNullOrEmpty ()) {
return source;
}
//
// Apply Sorting ...
if (isAscending) {
return source.OrderBy (sortByItem);
} else {
return source.OrderByDescending (sortByItem);
}
}
///
/// Apply Paging on a qury
///
///
///
///
///
///
public static IQueryable ApplyPaging (
this IQueryable source,
int? page,
int? pageSize
) {
//
if (!page.HasValue ||
page <= 0) {
page = 1;
}
//
if (!pageSize.HasValue ||
pageSize <= 0 ||
pageSize > XDataServiceConstants.MAX_AVAILABLE_PAGE_SIZE) {
pageSize = XDataServiceConstants.DEFAULT_PAGE_SIZE;
}
//
var pageVal = page.GetValueOrDefault ();
var pageSizeVal = pageSize.GetValueOrDefault ();
//
return source
.Skip ((pageVal - 1) * pageSizeVal)
.Take (pageSizeVal);
}
///
/// Apply Paging on a Enumerable
///
///
///
///
///
///
public static IEnumerable ApplyPaging (
this IEnumerable source,
int? page,
int? pageSize
) {
//
if (!page.HasValue ||
page <= 0) {
page = 1;
}
//
if (!pageSize.HasValue ||
pageSize <= 0 ||
pageSize > XDataServiceConstants.MAX_AVAILABLE_PAGE_SIZE) {
pageSize = XDataServiceConstants.DEFAULT_PAGE_SIZE;
}
//
var pageVal = page.GetValueOrDefault ();
var pageSizeVal = pageSize.GetValueOrDefault ();
//
return source
.Skip ((pageVal - 1) * pageSizeVal)
.Take (pageSizeVal);
}
}
}