public Parser(IEnumerable <KeyValuePair <string, StringValues> > configParams, IQueryable <T> queryable) { _queryable = queryable; _config = configParams.ToDictionary(k => k.Key, v => v.Value.First().Trim()); _type = typeof(T); //This associates class properties with corresponding datatable configuration options _propertyMap = (from param in _config join prop in _type.GetProperties() on param.Value equals prop.Name where Regex.IsMatch(param.Key, Constants.COLUMN_PROPERTY_PATTERN) let index = Regex.Match(param.Key, Constants.COLUMN_PROPERTY_PATTERN).Groups[1].Value let searchableKey = Constants.GetKey(Constants.SEARCHABLE_PROPERTY_FORMAT, index) let searchable = _config.ContainsKey(searchableKey) && _config[searchableKey] == "true" let orderableKey = Constants.GetKey(Constants.ORDERABLE_PROPERTY_FORMAT, index) let orderable = _config.ContainsKey(orderableKey) && _config[orderableKey] == "true" let filterKey = Constants.GetKey(Constants.SEARCH_VALUE_PROPERTY_FORMAT, index) let filter = _config.ContainsKey(filterKey)?_config[filterKey]:string.Empty // Set regex when implemented select new { index = int.Parse(index), map = new PropertyMap { Property = prop, Searchable = searchable, Orderable = orderable, Filter = filter } }).Distinct().ToDictionary(k => k.index, v => v.map); if (_propertyMap.Count == 0) { throw new Exception("No properties were found in request. Please map datatable field names to properties in T"); } if (_config.ContainsKey(Constants.DISPLAY_START)) { int.TryParse(_config[Constants.DISPLAY_START], out _skip); } if (_config.ContainsKey(Constants.DISPLAY_LENGTH)) { int.TryParse(_config[Constants.DISPLAY_LENGTH], out _take); } else { _take = 10; } _sortDisabled = _config.ContainsKey(Constants.ORDERING_ENABLED) && _config[Constants.ORDERING_ENABLED] == "false"; }
private void ApplySort() { var sorted = false; var paramExpr = Expression.Parameter(_type, "val"); // Enumerate the keys sort keys in the order we received them foreach (var param in _config.Where(k => Regex.IsMatch(k.Key, Constants.ORDER_PATTERN))) { // column number to sort (same as the array) int sortcolumn = int.Parse(param.Value); // ignore disabled columns if (!_propertyMap.ContainsKey(sortcolumn) || !_propertyMap[sortcolumn].Orderable) { continue; } var index = Regex.Match(param.Key, Constants.ORDER_PATTERN).Groups[1].Value; var orderDirectionKey = Constants.GetKey(Constants.ORDER_DIRECTION_FORMAT, index); // get the direction of the sort string sortdir = _config[orderDirectionKey]; var sortProperty = _propertyMap[sortcolumn].Property; var expression1 = Expression.Property(paramExpr, sortProperty); var propType = sortProperty.PropertyType; var delegateType = Expression.GetFuncType(_type, propType); var propertyExpr = Expression.Lambda(delegateType, expression1, paramExpr); // apply the sort (default is ascending if not specified) string methodName; if (string.IsNullOrEmpty(sortdir) || sortdir.Equals(Constants.ASCENDING_SORT, StringComparison.OrdinalIgnoreCase)) { methodName = sorted ? "ThenBy" : "OrderBy"; } else { methodName = sorted ? "ThenByDescending" : "OrderByDescending"; } _queryable = typeof(Queryable).GetMethods().Single( method => method.Name == methodName && method.IsGenericMethodDefinition && method.GetGenericArguments().Length == 2 && method.GetParameters().Length == 2) .MakeGenericMethod(_type, propType) .Invoke(null, new object[] { _queryable, propertyExpr }) as IOrderedQueryable <T>; sorted = true; } //Linq to entities needs a sort to implement skip //Not sure if we care about the queriables that come in sorted? IOrderedQueryable does not seem to be a reliable test if (!sorted) { var firstProp = Expression.Property(paramExpr, _propertyMap.First().Value.Property); var propType = _propertyMap.First().Value.Property.PropertyType; var delegateType = Expression.GetFuncType(_type, propType); var propertyExpr = Expression.Lambda(delegateType, firstProp, paramExpr); _queryable = typeof(Queryable).GetMethods().Single( method => method.Name == "OrderBy" && method.IsGenericMethodDefinition && method.GetGenericArguments().Length == 2 && method.GetParameters().Length == 2) .MakeGenericMethod(_type, propType) .Invoke(null, new object[] { _queryable, propertyExpr }) as IOrderedQueryable <T>; } }