Wie kann ich OrderBy auf ein IQueryable anwenden, indem ich einen Stringspaltennamen in einer generischen Erweiterungsmethode verwende?

public static IQueryable ApplySortFilter(this IQueryable query, string columnName) where T : EntityObject { var param = Expression.Parameter(typeof(T), "o"); var body = Expression.PropertyOrField(param,columnName); var sortExpression = Expression.Lambda(body, param); return query.OrderBy(sortExpression); } 

Da der Typ für OrderBy nicht aus sortExpression abgeleitet werden kann, muss er zur Laufzeit wie folgt angegeben werden:

 var sortExpression = Expression.Lambda(body, param); 

Oder

 return query.OrderBy(sortExpression); 

Ich glaube nicht, dass dies möglich ist, da TSortColumn nur zur Laufzeit ermittelt werden kann.

Gibt es einen Weg dahin?

Solutions Collecting From Web of "Wie kann ich OrderBy auf ein IQueryable anwenden, indem ich einen Stringspaltennamen in einer generischen Erweiterungsmethode verwende?"

Wir haben in einem LINQ to SQL-Projekt etwas ähnliches (nicht 100% gleich, aber ähnlich) gemacht. Hier ist der Code:

 public static IQueryable OrderBy(this IQueryable source, string ordering, params object[] values) { var type = typeof(T); var property = type.GetProperty(ordering); var parameter = Expression.Parameter(type, "p"); var propertyAccess = Expression.MakeMemberAccess(parameter, property); var orderByExp = Expression.Lambda(propertyAccess, parameter); MethodCallExpression resultExp = Expression.Call(typeof(Queryable), "OrderBy", new Type[] { type, property.PropertyType }, source.Expression, Expression.Quote(orderByExp)); return source.Provider.CreateQuery(resultExp); } 

Wir haben nicht wirklich ein generisches verwendet, wir hatten eine bekannte class, aber es sollte auf einem generischen funktionieren (ich habe den generischen Platzhalter dort platziert, wo er sein sollte).

Bearbeiten: Für absteigende Reihenfolge übergeben Sie OrderByDescending anstelle von “OrderBy”:

 MethodCallExpression resultExp = Expression.Call(typeof(Queryable), "OrderByDescending", new Type[] { type, property.PropertyType }, source.Expression, Expression.Quote(orderByExp)); 

Sie können auch Dynamic Linq verwenden

Info hier http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

C # hier herunterladen http://msdn.microsoft.com/en-us/vcsharp/bb894665.aspx

Dann fügen Sie einfach die Verwendung Linq.Dynamic; und Sie erhalten automatisch 2 zusätzliche Erweiterungsmethoden, die so verwendet werden können

 return query.OrderBy("StringColumnName"); 

Ich habe Ihre functionen erweitert, um Unterstützung für Untereigenschaften hinzuzufügen.

 private static LambdaExpression GenerateSelector(String propertyName, out Type resultType) where TEntity : class { // Create a parameter to pass into the Lambda expression (Entity => Entity.OrderByField). var parameter = Expression.Parameter(typeof(TEntity), "Entity"); // create the selector part, but support child properties PropertyInfo property; Expression propertyAccess; if (propertyName.Contains('.')) { // support to be sorted on child fields. String[] childProperties = propertyName.Split('.'); property = typeof(TEntity).GetProperty(childProperties[0]); propertyAccess = Expression.MakeMemberAccess(parameter, property); for (int i = 1; i < childProperties.Length; i++) { property = property.PropertyType.GetProperty(childProperties[i]); propertyAccess = Expression.MakeMemberAccess(propertyAccess, property); } } else { property = typeof(TEntity).GetProperty(propertyName); propertyAccess = Expression.MakeMemberAccess(parameter, property); } resultType = property.PropertyType; // Create the order by expression. return Expression.Lambda(propertyAccess, parameter); } private static MethodCallExpression GenerateMethodCall(IQueryable source, string methodName, String fieldName) where TEntity : class { Type type = typeof(TEntity); Type selectorResultType; LambdaExpression selector = GenerateSelector(fieldName, out selectorResultType); MethodCallExpression resultExp = Expression.Call(typeof(Queryable), methodName, new Type[] { type, selectorResultType }, source.Expression, Expression.Quote(selector)); return resultExp; } 

Sie können diese functionen verwenden wie:

 GenerateMethodCall(source, "OrderByDescending", fieldName); 

Ich habe Ihre Idee für die Erweiterungsmethode für OrderBy verwendet. Aber im Falle von “viele zu viele” bekomme ich Fehler. Zum Beispiel haben Sie Tabelle Site, Customer und Customer_site. Für die angegebene Site möchte ich nach Kundennamen und OrderBy-Erweiterung sortieren (wenn ich “site.customer” übergebe, wo der Kunde die Navigationseigenschaft hat), erhalte ich einen Fehler in der Zeile: propertyAccess = Expression.MakeMemberAccess (propertyAccess, property);

Das verwende ich (mit einigen Verbesserungen :-)):

 public static IQueryable OrderBy(this IQueryable source, string orderByValues) where TEntity : class { IQueryable returnValue = null; string orderPair = orderByValues.Trim().Split(',')[0]; string command = orderPair.ToUpper().Contains("DESC") ? "OrderByDescending" : "OrderBy"; var type = typeof(TEntity); var parameter = Expression.Parameter(type, "p"); string propertyName = (orderPair.Split(' ')[0]).Trim(); System.Reflection.PropertyInfo property; MemberExpression propertyAccess; if (propertyName.Contains('.')) { // support to be sorted on child fields. String[] childProperties = propertyName.Split('.'); property = typeof(TEntity).GetProperty(childProperties[0]); propertyAccess = Expression.MakeMemberAccess(parameter, property); for (int i = 1; i < childProperties.Length; i++) { Type t = property.PropertyType; if (!t.IsGenericType) { property = t.GetProperty(childProperties[i]); } else { property = t.GetGenericArguments().First().GetProperty(childProperties[i]); } propertyAccess = Expression.MakeMemberAccess(propertyAccess, property); } } else { property = type.GetProperty(propertyName); propertyAccess = Expression.MakeMemberAccess(parameter, property); } var orderByExpression = Expression.Lambda(propertyAccess, parameter); var resultExpression = Expression.Call(typeof(Queryable), command, new Type[] { type, property.PropertyType }, source.Expression, Expression.Quote(orderByExpression)); returnValue = source.Provider.CreateQuery(resultExpression); if (orderByValues.Trim().Split(',').Count() > 1) { // remove first item string newSearchForWords = orderByValues.ToString().Remove(0, orderByValues.ToString().IndexOf(',') + 1); return source.OrderBy(newSearchForWords); } return returnValue; } 

Grüße

Slobodan

Es scheint, dass dies der Weg ist, dies zu tun, um dies zu überprüfen:

 // ***** OrderBy(company => company) ***** // Create an expression tree that represents the expression // 'whereCallExpression.OrderBy(company => company)' MethodCallExpression orderByCallExpression = Expression.Call( typeof(Queryable), "OrderBy", new Type[] { queryableData.ElementType, queryableData.ElementType }, whereCallExpression, Expression.Lambda>(pe, new ParameterExpression[] { pe })); // ***** End OrderBy ***** 

Wenn Sie “System.Linq.Dynamic” -Paket dann hinzufügen können, zu einfach ohne Komplikationen,

fistt insatll Paket “System.Linq.Dynamic” von NuGet Paketmanager dann versuchen Sie wie unten, wie Sie brauchen,

Ex:

 public IQueryable GetWithInclude(Expression> predicate, List sortBy, int pageNo, int pageSize = 12, params string[] include) { try { var numberOfRecordsToSkip = pageNo * pageSize; var dynamic = DbSet.AsQueryable(); foreach (var s in include) { dynamic.Include(s); } return dynamic.OrderBy("CreatedDate").Skip(numberOfRecordsToSkip).Take(pageSize); } catch (Exception e) { throw new Exception(e.Message); } } 

Hoffe, das wird helfen

Ich habe diesen Code ein wenig korrigiert : https://Stackoverflow.com/a/1670085/5852630

Dieser Code arbeitet mit sequentieller Sortierung: zuerst “OrderBy”, dann “ThenBy” ausführen (nicht “OrderBy”!)

 public static IQueryable OrderBy(this IQueryable source, string orderByValues) where TEntity : class { IQueryable returnValue = null; string[] orderPairs = orderByValues.Trim().Split(','); Expression resultExpression = source.Expression; string strAsc = "OrderBy"; string strDesc = "OrderByDescending"; foreach (string orderPair in orderPairs) { if (string.IsNullOrWhiteSpace(orderPair)) continue; string[] orderPairArr = orderPair.Trim().Split(' '); string propertyName = orderPairArr[0].Trim(); string orderNarrow = orderPairArr.Length > 1 ? orderPairArr[1].Trim() : string.Empty; string command = orderNarrow.ToUpper().Contains("DESC") ? strDesc : strAsc; Type type = typeof(TEntity); ParameterExpression parameter = Expression.Parameter(type, "p"); System.Reflection.PropertyInfo property; Expression propertyAccess; if (propertyName.Contains('.')) { // support to be sorted on child fields. String[] childProperties = propertyName.Split('.'); property = typeof(TEntity).GetProperty(childProperties[0]); propertyAccess = Expression.MakeMemberAccess(parameter, property); for (int i = 1; i < childProperties.Length; i++) { Type t = property.PropertyType; if (!t.IsGenericType) { property = t.GetProperty(childProperties[i]); } else { property = t.GetGenericArguments().First().GetProperty(childProperties[i]); } propertyAccess = Expression.MakeMemberAccess(propertyAccess, property); } } else { property = type.GetProperty(propertyName); propertyAccess = Expression.MakeMemberAccess(parameter, property); } if (property.PropertyType == typeof(object)) { propertyAccess = Expression.Call(propertyAccess, "ToString", null); } LambdaExpression orderByExpression = Expression.Lambda(propertyAccess, parameter); resultExpression = Expression.Call(typeof(Queryable), command, new Type[] { type, property.PropertyType == typeof(object) ? typeof(string) : property.PropertyType }, resultExpression, Expression.Quote(orderByExpression)); strAsc = "ThenBy"; strDesc = "ThenByDescending"; } returnValue = source.Provider.CreateQuery(resultExpression); return returnValue; }