4

次の式を 1 つの式に結合しようとしています: item => item.sub, sub => sub.key を item => item.sub.key にします。これを行う必要があるのは、アイテム セレクターをキー セレクターに個別に渡す OrderBy メソッドを作成できるようにするためです。これは、OrderBy のオーバーロードの 1 つを使用して を提供することで実現できますが、IComparer<T>SQL には変換されません。

以下は、私が達成しようとしていることをさらに明確にするためのメソッド シグネチャと、機能しないがポイントを説明する必要がある実装です。

    public static IOrderedQueryable<TEntity> OrderBy<TEntity, TSubEntity, TKey>(
        this IQueryable<TEntity> source, 
        Expression<Func<TEntity, TSubEntity>> selectItem, 
        Expression<Func<TSubEntity, TKey>> selectKey)
        where TEntity : class
        where TSubEntity : class 
    {
        var parameterItem = Expression.Parameter(typeof(TEntity), "item");
        ...
        some magic
        ...
        var selector = Expression.Lambda(magic, parameterItem);
        return (IOrderedQueryable<TEntity>)source.Provider.CreateQuery(
            Expression.Call(typeof(Queryable), "OrderBy", new Type[] { source.ElementType, selector.Body.Type },
                 source.Expression, selector
                 ));
    } 

これは次のように呼び出されます。

.OrderBy(item => item.Sub, sub => sub.Key)

これは可能ですか?より良い方法はありますか?このように動作する OrderBy メソッドが必要な理由は、さまざまな方法で公開されますが、多くのエンティティに適用される複雑なキー選択式をサポートするためです。また、深いプロパティの文字列表現を使用してこれを行う方法を認識していますが、強く型付けしたままにしようとしています。

4

3 に答える 3

3

同じことが必要だったので、この小さな拡張メソッドを作成しました:

    /// <summary>
    /// From A.B.C and D.E.F makes A.B.C.D.E.F. D must be a member of C.
    /// </summary>
    /// <param name="memberExpression1"></param>
    /// <param name="memberExpression2"></param>
    /// <returns></returns>
    public static MemberExpression JoinExpression(this Expression memberExpression1, MemberExpression memberExpression2)
    {
        var stack = new Stack<MemberInfo>();
        Expression current = memberExpression2;
        while (current.NodeType != ExpressionType.Parameter)
        {
            var memberAccess = current as MemberExpression;
            if (memberAccess != null)
            {
                current = memberAccess.Expression;
                stack.Push(memberAccess.Member);
            }
            else
            {
                throw new NotSupportedException();
            }
        }


        Expression jointMemberExpression = memberExpression1;
        foreach (var memberInfo in stack)
        {
            jointMemberExpression = Expression.MakeMemberAccess(jointMemberExpression, memberInfo);
        }

        return (MemberExpression) jointMemberExpression;
    }
于 2015-10-29T15:49:30.983 に答える
1

あなたが持っているものはsotringであり、次に投影し、そして再びソートします。

.OrderBy(x => x.Sub)
    .Select(x => x.Sub)
        .OrderBy(x => x.Key)

あなたの方法は次のようになります:

public static IOrderedQueryable<TSubEntity> OrderBy<TEntity, TSubEntity, TKey>(
    this IQueryable<TEntity> source, 
    Expression<Func<TEntity, TSubEntity>> selectItem, 
    Expression<Func<TSubEntity, TKey>> selectKey)
    where TEntity : class
    where TSubEntity : class 
{
    return (IOrderedQueryable<TSubEntity>)source.
        OrderBy(selectItem).Select(selectItem).OrderBy(selectKey)
}

これはSQLによって実行されますが、お気づきかもしれませんが、ここで戻り型をIOrderedQueryable<TSubEntity>に変更する必要がありました。あなたはそれを回避できますか?

于 2009-02-18T07:02:16.530 に答える