0

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 を適用するにはどうすればよいですか?から借用し たものです。

4

3 に答える 3

2

あなたのことを正しく理解しているかどうかはよくわかりませんが、私は数か月前に同じ状況にあったと思います。ここに投稿されたコードは私の解決策でした。

特に 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());
于 2013-01-24T16:10:37.817 に答える
1

必要以上に難しくしていると思います。コードの最初の部分 ( 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()

于 2013-01-24T19:05:08.740 に答える
0

あなたはもう途中です。すでに順序付けられた式があるので、Queryable.OrderBy式で式呼び出しを使用するだけですQueryable.Where(または、その逆も重要ではありません)。

if(null != restrictedProperty )
{
    var notEqualExp = Expression.NotEqual(parameter,
                            Expression.Constant(restrictedValue, typeof(string)));
    resultExp = Expression.Call(
            typeof(Queryable), 
            "Where", 
            new Type[] { type }, 
            resultExp, 
            Expression.Lambda(notEqualExp, parameter));
}

しばらくの間、手作業で式を作成する作業を行っていないため、これは純粋にメモリから行われています。ただし、少なくとも開始して、作業するための何かを提供する必要があります。

PSOrderByメソッドを呼び出す前に、実際にこのチェックを実行します。そうすれば、Queryably.Where(...).OrderBy(...)代わりになります。しかし、これがとにかくプロバイダーによって翻訳されているのであれば、問題ではないはずです。ただし、生成されたクエリのあいまいさを減らすために私が行うことです。

于 2013-01-24T18:35:59.223 に答える