public static IQueryable<TResult> ApplySortFilter<T, TResult>(this IQueryable<T> 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);
}
OrderBy의 유형은 sortExpression에서 유추되지 않기 때문에 런타임에 다음과 같이 지정해야합니다.
var sortExpression = Expression.Lambda<T, TSortColumn>(body, param);
또는
return query.OrderBy<T, TSortColumn>(sortExpression);
나는 이것이 가능하다고 생각하지 않지만 TSortColumn은 런타임 중에 만 결정할 수 있기 때문에 가능합니다.
이 문제를 해결할 방법이 있습니까?
답변
LINQ to SQL 프로젝트에서 비슷한 작업을 수행했습니다 (100 % 동일하지는 않지만 유사 함). 코드는 다음과 같습니다.
public static IQueryable<T> OrderBy<T>(this IQueryable<T> 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<T>(resultExp);
}
우리는 실제로 제네릭을 사용하지 않았고 알려진 클래스가 있었지만 제네릭에서 작동해야합니다 (제네릭 자리 표시자를 있어야하는 곳에 넣었습니다).
편집 : 내림차순 OrderByDescending
의 경우 “OrderBy”대신 전달하십시오 .
MethodCallExpression resultExp = Expression.Call(typeof(Queryable), "OrderByDescending", new Type[] { type, property.PropertyType }, source.Expression, Expression.Quote(orderByExp));
답변
Dynamic Linq를 사용할 수도 있습니다.
여기에서 C # 다운로드
http://msdn.microsoft.com/en-us/vcsharp/bb894665.aspx
그런 다음 using Linq.Dynamic을 추가합니다. 이렇게 사용할 수있는 2 개의 추가 확장 메서드가 자동으로 생성됩니다.
return query.OrderBy("StringColumnName");
답변
하위 속성에 대한 지원을 추가하기 위해 기능을 확장했습니다.
private static LambdaExpression GenerateSelector<TEntity>(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<TEntity>(IQueryable<TEntity> source, string methodName, String fieldName) where TEntity : class
{
Type type = typeof(TEntity);
Type selectorResultType;
LambdaExpression selector = GenerateSelector<TEntity>(fieldName, out selectorResultType);
MethodCallExpression resultExp = Expression.Call(typeof(Queryable), methodName,
new Type[] { type, selectorResultType },
source.Expression, Expression.Quote(selector));
return resultExp;
}
다음과 같은 기능을 사용할 수 있습니다.
GenerateMethodCall<TEntity>(source, "OrderByDescending", fieldName);
답변
OrderBy의 확장 방법에 대한 아이디어를 사용했습니다. 그러나 “다 대다”의 경우 오류가 발생합니다. 예를 들어 Site, Customer 및 Customer_site 테이블이 있습니다. 주어진 사이트에 대해 고객 이름과 OrderBy 확장 (고객이 탐색 속성 인 “site.customer”를 전달할 때)별로 정렬하려고합니다. 줄에 오류가 발생합니다. propertyAccess = Expression.MakeMemberAccess (propertyAccess, property);
이것은 내가 사용하는 것입니다 (일부 개선 사항 :-)).
public static IQueryable<TEntity> OrderBy<TEntity>(this IQueryable<TEntity> source, string orderByValues) where TEntity : class
{
IQueryable<TEntity> 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<TEntity>(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;
}
문안 인사
슬로 보단
답변
이것이 다음 을 확인하는 방법 인 것 같습니다 .
// ***** 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<Func<string, string>>(pe, new ParameterExpression[] { pe }));
// ***** End OrderBy *****
답변
“System.Linq.Dynamic”패키지를 추가 할 수 있다면 복잡하지 않고 Too easy,
NuGet 패키지 관리자에서 fisrt insatll 패키지 “System.Linq.Dynamic”을 설치 한 다음 필요에 따라 다음과 같이 시도하십시오.
전의:
public IQueryable<TEntity> GetWithInclude(Expression<Func<TEntity, bool>> predicate,
List<string> 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);
}
}
이것이 도움이되기를 바랍니다.
답변
이 코드를 약간 수정했습니다 : https://stackoverflow.com/a/1670085/5852630
이 코드는 순차 정렬과 함께 작동합니다. 먼저 “OrderBy”를 실행 한 다음 “ThenBy”( “OrderBy”가 아님!)
public static IQueryable<TEntity> OrderBy<TEntity>(this IQueryable<TEntity> source, string orderByValues) where TEntity : class
{
IQueryable<TEntity> 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<TEntity>(resultExpression);
return returnValue;
}