/ / Multisorting IQueryable mit einem String-Spaltennamen innerhalb einer generischen Erweiterungsmethode? - c #, Entity-Framework, linq, Reflexion

Multisorting IQueryable mit einem String-Spaltennamen innerhalb einer generischen Erweiterungsmethode? - c #, Entity-Framework, linq, Reflexion

Ich muss die Sammlung nach ein paar Spalten sortieren. Ich habe eine Liste von Objekten, wobei jedes Objekt columnName und sortDir (Asc oder Desc) enthält. Also, wie kann ich es tun? Ich habe versucht, es durch Reflexion zu tun, aber ich habe den Fehler:

Message: `LINQ to Entities does not recognize the method "Int32 Parse(System.String)" method, and this method cannot be translated into a store expression.`
StackTrace: `   at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.DefaultTranslator.Translate(ExpressionConverter parent, MethodCallExpression call)
at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter parent, MethodCallExpression linq)
at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)
at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)
at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.EqualsTranslator.TypedTranslate(ExpressionConverter parent, BinaryExpression linq)
at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)
at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)
at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateLambda(LambdaExpression lambda, DbExpression input)
at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateLambda(LambdaExpression lambda, DbExpression input, DbExpressionBinding& binding)
at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.OneLambdaTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, DbExpression& source, DbExpressionBinding& sourceBinding, DbExpression& lambda)
at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.OneLambdaTranslator.Translate(ExpressionConverter parent, MethodCallExpression call)
at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.SequenceMethodTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, SequenceMethod sequenceMethod)
at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter parent, MethodCallExpression linq)
at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)
at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)
at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.OneLambdaTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, DbExpression& source, DbExpressionBinding& sourceBinding, DbExpression& lambda)
at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.OneLambdaTranslator.Translate(ExpressionConverter parent, MethodCallExpression call)
at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.SequenceMethodTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, SequenceMethod sequenceMethod)
at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter parent, MethodCallExpression linq)
at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)
at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)
at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.Convert()
at System.Data.Entity.Core.Objects.ELinq.ELinqQueryState.GetExecutionPlan(Nullable`1 forMergeOption)
at System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClass7.<GetResults>b__6()
at System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
at System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClass7.<GetResults>b__5()
at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)
at System.Data.Entity.Core.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)
at System.Data.Entity.Core.Objects.ObjectQuery`1.<System.Collections.Generic.IEnumerable<T>.GetEnumerator>b__0()
at System.Data.Entity.Internal.LazyEnumerator`1.MoveNext()
at System.Linq.SystemCore_EnumerableDebugView`1.get_Items()`

Ich lese ein paar Artikel Dies und Dies, aber ihre Lösungen helfen mir nicht. Vielleicht hat jemand Ideen für mich?

Code:

public static IQueryable<T> SortByParams<T>(IQueryable<T> collection, List<SortBy> sorting)
{
bool firstOrder = true;
IOrderedQueryable<T> sortedRes = null;
foreach (SortBy sort in sorting)
{
try
{
if (firstOrder)
{
if (sort.sortDir.ToLower() == "desc")
{
sortedRes = collection.OrderByDescending(obj => obj.GetType().GetProperty(sort.columnName).GetValue(obj, null));
}
else
{
sortedRes = collection.OrderBy(obj => obj.GetType().GetProperty(sort.columnName).GetValue(obj, null));
}
firstOrder = false;
}
else
{
if (sort.sortDir.ToLower() == "desc")
{
sortedRes = sortedRes.ThenByDescending(obj => obj.GetType().GetProperty(sort.columnName).GetValue(obj, null));
}
else
{
sortedRes = sortedRes.ThenBy(obj => obj.GetType().GetProperty(sort.columnName).GetValue(obj, null));
}
}
}
catch (Exception) { }
collection = sortedRes;
}
return collection;
}

Antworten:

1 für die Antwort № 1

Ausdrücke wie diese

obj => obj.GetType().GetProperty(sort.columnName).GetValue(obj, null)

könnte im Kontext von LINQ To Objects anwendbar sein, aber definitiv nicht in LINQ to Entities.

Im Allgemeinen kann man Reflexion (und viele andere) nicht verwendenandere Methoden) innerhalb des LINQ to Entities-Abfrageausdrucks, da sie nicht in SQL übersetzt werden können (oder der Abfrageanbieter sie nicht erkennt und verarbeitet) NotSupportedException).

Statt Reflektion sollten Sie den Ausdruck mit verwenden System.Linq.Expressions.

Zum Beispiel so:

public static IQueryable<T> SortByParams<T>(this IQueryable<T> source, List<SortBy> sorting)
{
var queryExpr = source.Expression;
string methodAsc = "OrderBy";
string methodDesc = "OrderByDescending";
foreach (var item in sorting)
{
var selectorParam = Expression.Parameter(typeof(T), "e");
var selector = Expression.Lambda(Expression.PropertyOrField(selectorParam, item.columnName), selectorParam);
var method = string.Equals(item.sortDir, "desc", StringComparison.OrdinalIgnoreCase) ? methodDesc : methodAsc;
queryExpr = Expression.Call(typeof(Queryable), method,
new Type[] { selectorParam.Type, selector.Body.Type },
queryExpr, Expression.Quote(selector));
methodAsc = "ThenBy";
methodDesc = "ThenByDescending";
}
return source.Provider.CreateQuery<T>(queryExpr);
}