/// <summary> /// Applies default sorting behavior to the query. /// These sorting behaviors are those added with [DefaultOrderBy] attributes on model properties. /// If no default orderings are found, an attempt will be made to sort on a property called "Name" if one exists, /// and finally, on the primary key of the model being requested. /// This is called by ApplyListSorting when constructing a list result. /// </summary> /// <param name="query">The query to sort.</param> /// <returns>The new query with additional sorting applied.</returns> public virtual IQueryable <T> ApplyListDefaultSorting(IQueryable <T> query) { // Use the DefaultOrderBy attributes if available var defaultOrderBy = ClassViewModel.DefaultOrderByClause(); if (defaultOrderBy != null) { query = query.OrderBy(defaultOrderBy); } return(query); }
protected async Task <ListResult> ListImplementation(ListParameters listParameters) { try { IQueryable <T> result = GetListDataSource(listParameters); // Add the Include statements to the result to grab the right object graph. Passing "" gets the standard set. if ((result is DbSet <T>) && string.Compare(listParameters.Includes, "none", StringComparison.InvariantCultureIgnoreCase) != 0) { result = result.Includes(listParameters.Includes); } // Add filters for the where clause, etc. result = AddFilters(result, listParameters); // Change to a list so we can sort on other fields not just what is in the database if we need to. // TODO: Make this more flexible to allow for searching on computed terms. This could be automatic by detecting fields that are in the database. // IEnumerable<T> result2 = result; // if (listParameters.ToList) result2 = result.ToList() as IQueryable<T>; // Above was removed because IEnumerable uses different extension methods than iQueryable causing very inefficient SQL to be used. // Add sorting. var orderByParams = listParameters.OrderByList; if (orderByParams.Any()) { foreach (var orderByParam in orderByParams) { string fieldName = orderByParam.Key; var prop = ClassViewModel.PropertyByName(fieldName); if (!fieldName.Contains(".") && prop != null && prop.IsPOCO) { string clause = prop.Type.ClassViewModel.DefaultOrderByClause($"{fieldName}."); clause = clause.Replace("ASC", orderByParam.Value.ToUpper()); clause = clause.Replace("DESC", orderByParam.Value.ToUpper()); result = result.OrderBy(clause); } else { result = result.OrderBy(string.Join(", ", orderByParams.Select(f => $"{fieldName} {f.Value}"))); } } } else { // Use the DefaultOrderBy attributes if available var defaultOrderBy = ClassViewModel.DefaultOrderByClause(); if (defaultOrderBy != null) { result = result.OrderBy(defaultOrderBy); } // Use the Name property if it exists. else if (ClassViewModel.Properties.Any(f => f.Name == "Name")) { result = result.OrderBy("Name"); } // Use the ID property. else { result = result.OrderBy(ClassViewModel.PrimaryKey.Name); } } // Get a count int totalCount; if (result is IAsyncQueryProvider) { totalCount = await result.CountAsync(); } else { totalCount = result.Count(); } // Add paging. int page = listParameters.Page ?? 1; int pageSize = listParameters.PageSize ?? DefaultPageSize; // Fix the page numbers if necessary if ((page - 1) * pageSize > totalCount) { page = (int)((totalCount - 1) / pageSize) + 1; } // Skip zero has issues. // Due to a bug in both RC1 (fails in SQL 2008) and RC2 (doesn't get all included children) if (page > 1) { result = result.Skip((page - 1) * pageSize); } result = result.Take(pageSize); // Make the database call IEnumerable <T> result2; if (result is IAsyncQueryProvider) { result2 = await result.ToListAsync(); } else { result2 = result.ToList(); } // Add external entities result2.IncludesExternal(listParameters.Includes); // Exclude certain data if (new T() is IExcludable) { foreach (var obj in result2) { ((IExcludable)obj).Exclude(listParameters.Includes); } } // Allow for security trimming // TODO: This needs to be adjusted to handle paging correctly. var result3 = result2.Where(f => BeforeGet(f)); var tree = result.GetIncludeTree(); IEnumerable <TDto> result4 = result3.ToList().Select(obj => MapObjToDto(obj, listParameters.Includes, tree)).ToList(); if (listParameters.FieldList.Any()) { return(new ListResult(result4.ToList().Select("new (" + string.Join(", ", listParameters.FieldList) + ")"), page, totalCount, pageSize)); } return(new ListResult(result4, page, totalCount, pageSize)); } catch (Exception ex) { Response.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError; if (Logger != null) { Logger.LogError(ex.Message, ex); } return(new ListResult(ex)); } }