Tは、特定のプロパティを持つ場合と持たない場合がある型です。「City」と言いましょう。 「City」という名前のプロパティを持つタイプの場合、Gothamの居住者のみが返され、ソートされるようにレコードを制限したいと思います。
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));
string propertyToRestrictOn = "City";
string restrictedValue = "Gotham";
var restrictedProperty = type.GetProperty(propertyToRestrictOn);
if(null ! = restrictedProperty )
{
// TODO: What to add here so than only those records are returned that have a
// property named City and the value is 'Gotham'???
}
return source.Provider.CreateQuery<T>(resultExp);
}
可能であれば、ここに参考文献を挙げてリンクしてください。さらに複雑なクエリを作成する必要がある場合に備えて、AndやORをミックスしてください。
コードは、汎用の拡張メソッド内で文字列の列名を使用してIQueryableにOrderByを適用するにはどうすればよいですか?
私はあなたが必要以上にこれを難しくしていると思います。コードの最初の部分( OrderBy()
)では、実際にはクエリ式全体を生成する必要はありません。その中にラムダを生成するだけです。そして、2番目の部分(オプションのWhere()
)では、ほとんど同じことができますExpression.Equal()
とExpression.Constant()
追加するだけです。
public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string ordering)
{
var type = typeof(T);
var property = type.GetProperty(ordering);
var parameter = Expression.Parameter(type, "p");
var propertyAccess = Expression.MakeMemberAccess(parameter, property);
// necessary for value types to work
var cast = Expression.Convert(propertyAccess, typeof(object));
var orderByExp = Expression.Lambda<Func<T, object>>(cast, parameter);
IQueryable<T> result = source.OrderBy(orderByExp);
string propertyToRestrictOn = "City";
string restrictedValue = "Gotham";
var restrictedProperty = type.GetProperty(propertyToRestrictOn);
if (restrictedProperty != null)
{
var restrictionParameter = Expression.Parameter(type, "p");
var restrictionPropertyAccess =
Expression.MakeMemberAccess(restrictionParameter, restrictedProperty);
var restrictionEquality =
Expression.Equal(restrictionPropertyAccess,
Expression.Constant(restrictedValue));
var whereExp =
Expression.Lambda<Func<T, bool>>(restrictionEquality, restrictionParameter);
result = result.Where(whereExp);
}
return result;
}
また、メソッドが単に順序付けするだけではない場合は、 OrderBy()
と呼ばない方がいいと思います。
私があなたを正しく理解したかどうかはよくわかりませんが、私は数ヶ月前に同じ状況にいたと思います。投稿コードここでは、私の解決策でした。
特に24行目に興味があると思います。
編集:
PropertyInfo p = ... // I used reflection in my examply to get properties with a certain Attribute
var expressionParameter = Expression.Parameter(typeof(SomeClass), "lambda");
var parameter = new [] { expressionParameter };
var propertyAccess = Expression.Property(expressionParameter, p);
var nullCheck = Expression.NotEqual(propertyAccess, Expression.Constant(null, p.PropertyType));
var nullCheckLambda = Expression.Lambda<Func<SomeClass, Boolean>>(nullCheck, parameter);
var containsMethodInfo = typeof(String).GetMethod("Contains", new[] { typeof(String) });
var contains = Expression.Call(propertyAccess, containsMethodInfo, Expression.Constant("ell"));
var containsLambda = Expression.Lambda<Func<SomeClass, Boolean>>(contains, new[] { expressionParameter });
var predicate = Expression.Lambda<Func<SomeClass, Boolean>>(
// line 24
Expression.AndAlso(nullCheckLambda.Body, containsLambda.Body), parameter);
Console.WriteLine(predicate.ToString());