Beispiel #1
0
        /// <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());
        }