/// <summary> /// Retrieve a word list using the specified criteria. /// </summary> /// <typeparam name="TInType">An object type mapped to words stored in the database</typeparam> /// <typeparam name="TOrderingType">A type of value to use for ordering</typeparam> /// <typeparam name="TRetType">The type to be returned by creating a loaded word with selector</typeparam> /// <param name="keyExpr">An expression to get the values needed for ordering</param> /// <param name="selector">A selector to convert the return values</param> /// <param name="order">Sorting order</param> /// <param name="page">The page to load. It works by skipping <code>(page - 1) * limit</code>.</param> /// <param name="limit">Number of words per page. Default value is 50.</param> /// <returns>Asynchronous operation to return converted words</returns> public static async Task <List <TRetType> > LoadWords <TInType, TRetType>(WordContext ctx, ListState state, Func <TInType, TRetType> selector, WordViewModel model, int limit = PageUtils.LimitPerPage, params Func <TInType, bool>[] filters) where TInType : class where TRetType : class { if (selector == null) { throw new ArgumentNullException(nameof(selector)); } if (limit <= 0 || limit > 2000) { throw new ArgumentOutOfRangeException(nameof(limit)); } // Generate a query dynamically. string queryOrder = ""; switch (model.Order) { case Order.Asc: queryOrder = "OrderBy"; break; case Order.Desc: queryOrder = "OrderByDescending"; break; default: break; } IEnumerable <TInType> query = ctx.Set <TInType>(); if (!string.IsNullOrEmpty(queryOrder)) { var inType = typeof(TInType); PropertyInfo pInfo; var param = Expression.Parameter(typeof(TInType), "w"); LambdaExpression keyExpr; if (model.Column == null) { keyExpr = Expression.Lambda(Expression.PropertyOrField(param, nameof(Word.WordID)), param); pInfo = inType.GetProperty(nameof(Word.WordID)); } else { keyExpr = Expression.Lambda(Expression.PropertyOrField(param, model.Column), param); pInfo = inType.GetProperty(model.Column); } var queryableType = typeof(Queryable); var method = queryableType.GetMethods() .Where(m => m.Name == queryOrder && m.IsGenericMethodDefinition) .Where(m => m.GetParameters().Count() == 2) .Single(); MethodInfo order = method.MakeGenericMethod(typeof(TInType), pInfo.PropertyType); query = (IOrderedQueryable <TInType>)order.Invoke(order, new object[] { query, keyExpr }); } foreach (var filter in filters) { query = query.Where(filter); } state.TotalCount = query.Count(); query = query.Skip((model.Page - 1) * limit); query = query.Take(limit); return(await query .ToAsyncEnumerable() .Select(selector) .ToList()); }