2016-07-14 7 views
3

DbContextが大量にあります。すべてのDbSetには、指定されたpageSizeを持ち、特定のsortOrderによって順序付けされたセットの項目のページを取得する関数が必要です。ような何か:Func <TSource、int>とintを比較して式<Func <TSource、bool>を作成する方法

var pageItems = dbContext.Posts 
    .Where(post => post.BlogId == blogId) 
    .OrderBy(some sortorder) 
    .Skip(pageNr * pageSize) 
    .Take(pageSize); 

私はすべての私のDbSetsでこれを行うことができるようにしたいので、私はパラメータの一つは、この外部キーが持つべき値を比較し、別の外部キーを指定する拡張メソッドを作成しました。どこに適した述語でkeySelectorを変換する方法

public static IQueryable<TSource> GetPage<TSource>(this IQueryable<TSource> source, 
    int pageNr, int pageSize, 
    Expression<Func<TSource, Tproperty>> keySelector, Tproperty comparisonValue) 
{ 
    return source 
    .Where(???) 
    .OrderBy(some sortorder) 
    .Skip(pageNr * pageSize) 
    .Take(pageSize); 
} 

+0

Jon Skeet到着 –

+0

'Expression.LessThan'を使って、' keySelector'と 'comprasionValue'を' Expression.Constant'に変換してみてください。 –

+0

'Where'が解決されたとしましょう。あなたは 'OrderBy'を解決する方法を教えてください。 –

答えて

1

あなたはExpression<Func<TSource, Tproperty>> keySelectorからExpression<Func<TSource, boolean>>とそれがで翻訳することができるような方法でTproperty comparisonValueを取得する方法を探していますEntity Frameworkによる式の格納些細な

public static Expression<Func<TSource, bool>> KeyPredicateNaive<TSource, Tproperty>(Expression<Func<TSource, Tproperty>> keySelector, Tproperty comparisonValue) 
{ 
    return (TSource source) =>EqualityComparer<Tproperty>.Default.Equals(keySelector.Compile()(source), comparisonValue); 
} 

が動作しないことを意味します

。これをストア式に変換することはできません。

手動で式を構築する必要があります。私たちが必要とするのは、左の値としてのキーセレクターと、右の値としての値としての比較値を持つ定数式です。

public static Expression<Func<TSource, bool>> KeyPredicate<TSource, Tproperty>(Expression<Func<TSource, Tproperty>> keySelector, Tproperty comparisonValue) 
{ 
    var bd = Expression.Equal(keySelector.Body, Expression.Constant(comparisonValue)); 
    return Expression.Lambda<Func<TSource, bool>>(bd, keySelector.Parameters); 
} 

結果はwhereクラスに渡すことができます。コンパイルして実行するようにスリムにすると、メソッドは次のようになります

public static IQueryable<TSource> GetPage<TSource>(this IQueryable<TSource> source, 
    int pageSize, 
    Expression<Func<TSource, Tproperty>> keySelector, Tproperty comparisonValue) 
{ 
    return source 
    .Where(KeyPredicate(keySelector, comparisonValue) 
    .Take(pageSize); 
} 

私はこれを使用しますか?おそらくそうではありません。式を自分で構築するのではなく、ラムダとして述語を直接関数に渡す方が簡単です。しかし、それは確かに可能性です。

+0

このメソッドは機能します。私はすでにあなたのように表現を作成するための記事をいくつか見つけました。しかし、私はBinaryExpressonからラムダ式を作成する方法を見つけることができませんでした。あなたは正しいですが、Func を渡すのではなく、Func を渡す方が簡単です。同じレベルの型チェックを行います。 –

+0

まだ、あなたのツールベルトにこの技術を持たせることは良いことです。次回は、同様のことを考えているなら、それが良いアイデアかどうかを判断しやすくなります。 – Martijn

+0

2時間前に与えられたこの回答と同じhttp://stackoverflow.com/a/38372514/360211 – weston

0

クエリ可能なソースへの拡張機能を作成していますか?だから表現やフィルタソースを渡す:

public static IQueryable<TSource> GetPage<TSource, TKey>(this IQueryable<TSource> source, 
    Expression<Func<TSource, bool>> predicate, 
    Expression<Func<TSource, TKey>> keySelector, 
    int pageNr, int pageSize 
    ) 
{ 
    return source 
     .Where(predicate) 
     .OrderBy(keySelector) 
     .Skip(pageNr * pageSize) 
     .Take(pageSize); 
} 

使用法:あなたはソート(第2式)で問題を抱えているあなたのアプローチで、あなたが得るすべては、2つのパラメータの代わりにp => p.Author, "Bob"を渡している。

db.Posts.GetPage(p => p.Author == "Bob", p => p.Date, 5, 10); 

すぐ使用できる1つの式p => p.Author == "Bob"を渡します。


しかし、私はGetPageメソッドから述語とkeySelectorを移動します。 のみ(メソッド名の状態など)ページングでこのメソッドフォーカスをしてみましょう:

public static IQueryable<TSource> GetPage<TSource, TKey>(this IQueryable<TSource> source, 
    int pageNr, int pageSize) 
{ 
    return source.Skip(pageNr * pageSize).Take(pageSize); 
} 

使用法:

db.Posts.Where(p => p.Author == "Bob").OrderBy(p => p.Date).GetPage(5, 10); 

それとも、リポジトリ

postsRepository.GetByAuthor("Bob").GetPage(5, 10); 
0

はこれを試してみて、それかどうかを確認している場合助けてください

Expression<Func<TSource, bool>> keySelector 
あなたは

sealed class SwapVisitor : ExpressionVisitor 
{ 
    private readonly Expression _from; 
    private readonly Expression _to; 

    public SwapVisitor(Expression from, Expression to) 
    { 
     _from = from; 
     _to = to; 
    } 

    public override Expression Visit(Expression node) 
    { 
     return node == _from ? _to : base.Visit(node); 
    } 
} 

static Expression<Func<TInput, bool>> Combine<TInput, TOutput>(
    Expression<Func<TInput, TOutput>> transform, 
    Expression<Func<TOutput, bool>> predicate) 
{ 
    var swap = new SwapVisitor(predicate.Parameters[0], transform.Body); 
    return Expression.Lambda<Func<TInput, bool>>(
     swap.Visit(predicate.Body), transform.Parameters); 
} 

することができます:

.Where(Combine(keySelector, key => key == comparisonValue)) 

だから、渡された式keySelectorの本体と、新しいExpressionを作成しているこのコードを考える

または単に

Func<TSource, bool> keySelector 
+0

問題は、私は式>を持っていないということです。私はExpression >を持っており、これをintと比較して式>を取得したいと考えています。 –

2

おかげで、どのようにどこに適した述語でkeySelectorを変換するには?

これは簡単ですが、どのように注文を処理するのか分かりません。とにかく、ここであなたが求めているものを行うことができる方法:

public static IQueryable<TSource> GetPage<TSource, TKey>(this IQueryable<TSource> source, 
    int pageNr, int pageSize, 
    Expression<Func<TSource, TKey>> keySelector, TKey comparisonValue) 
{ 
    var predicate = Expression.Lambda<Func<TSource, bool>>(
     Expression.Equal(keySelector.Body, Expression.Constant(comparisonValue)), 
     keySelector.Parameters); 

    return source 
     .Where(predicate) 
     //.OrderBy(some sortorder) ?? 
     .Skip(pageNr * pageSize) 
     .Take(pageSize); 
} 
関連する問題