4

この質問に対する答えは「いいえ」だと思いますが、とにかく行きます。

基本的に、Linq2Sql生成された型を持つデータ プロバイダーがあります。プロパティ名が (この質問のために) 関連する生成された型のプロパティ名と完全に一致するビジネス オブジェクトもあります。ビジネス タイプはアプリケーション全体で使用され、生成されたタイプはデータベースへのアクセスにのみ使用されます。この設定は多くの理由で望ましいため、変更が必要な回答を提案しないでください。

UIレイヤーには、ユーザーが検索方法を調整できるようにするさまざまなコントロールがあります。検索するフィールド、検索用語など。これらのコントロールを使用してFunc<T, bool>、検索条件/クエリをカプセル化する適切なデリゲートを作成できます。私が抱えている問題はFunc、型パラメーターがビジネス オブジェクトであるデリゲートが作成され、Tそれがデータ アクセス層に渡されるときに、代わりに関連する生成型である必要があることです。

私の質問は、同じ条件を維持しながら、Funcデリゲートのジェネリック型パラメーターをビジネスオブジェクト型から関連する生成型に変更することは可能ですか?

eg. can Func<MasterTrack, bool>   =>   Func<DbMasterTrack, bool> when properties match?

また、ユーザーが選択したすべての検索パラメーターをデータ アクセス レイヤーに渡すこともできますが、かなりの数があるため、それを避けたいと考えていたことにも注意してください。

4

2 に答える 2

3

それが可能だとは思いませんが、次のことを行うことで逃げることができます:

  • に暗黙DbMasterTrack的に変換可能にしMasterTrackます。
  • クエリを実行するときFunc<MasterTack,bool>は、Func<DbMasterTrack,bool>.

また、そのFunc<T, bool>代わりにExpression<Func<T, bool>を使用している場合、実際にはデータベース レベルで結果セットをフィルタリングしていないことに注意する必要がありますが、それは既に認識していることかもしれません。

例は次のとおりです。

class MasterTrack
{
    public int Id { get; set; }
    public string Name { get; set; }
}
class DbMasterTrack
{
    public int Id { get; set; }
    public string Name { get; set; }
    public static implicit operator MasterTrack(DbMasterTrack @this)
    {
        return new MasterTrack { Id = @this.Id, Name = @this.Name };
    }
}
class Program
{
    static void Main(string[] args)
    {
        var tracks = new List<DbMasterTrack>
        {
            new DbMasterTrack { Id = 1, Name = "T1" },
            new DbMasterTrack { Id = 2, Name = "T2" },
        };

        Func<MasterTrack, bool> query = t => t.Id == 1;

        var result = tracks.Where((Func<DbMasterTrack, bool>)(t => query(t)));

        foreach (var item in result)
        {
            Console.WriteLine("{0}|{1}", item.Id, item.Name);
        }
    }
}
于 2012-08-16T11:40:02.683 に答える
2

いくつかのこと

  1. Linq2Sql は、 のExpression<Func<T, bool>>代わりに を使用することもできますFunc<T, bool>

  2. のタイプを変更することはできません。Expression<Func<T, bool>>

  3. Expression<Func<T, bool>>タイプ T を別のタイプに置き換える場所をコピー/再作成することが可能です。

  4. Linq2Sql は、その式でインターフェイス タイプを受け入れません。したがって、実際の型を「抽象化」するためのインターフェイスを作成することを考えると、それは機能しません。

今、私はかつて次のコードを作成したExpression<Func<T2, bool>>からを作成します。Expression<Func<T, bool>>式で可能なすべてのパスがサポートされているわけではないため、「完全」ではありません。しかし、値のプロパティをチェックする基本および/または組み合わせ (< > = != または組み合わせ) は、その時点で正常に機能していました。

このコードを使用すると、次のことができます。

Expression<Func<MasterTrack, bool>> criteria = m => m.Id == 1;
Expression<Func<DbMasterTrack, bool>> dbCriteria = ExpressionRewriter.CastParam<MasterTrack, DbMasterTrack>(criteria);

どうぞ。

public static class ExpressionRewriter {
    /// <summary>
    /// Casts the param of an expression.
    /// </summary>
    /// <typeparam name="TIn">The type of the in.</typeparam>
    /// <typeparam name="TOut">The type of the out.</typeparam>
    /// <param name="inExpr">The in expr.</param>
    /// <returns></returns>
    public static Expression<Func<TOut, bool>> CastParam<TIn, TOut>(Expression<Func<TIn, bool>> inExpr) {
        if (inExpr.NodeType == ExpressionType.Lambda &&
            inExpr.Parameters.Count > 0) {

            var inP = inExpr.Parameters[0];
            var outP = Expression.Parameter(typeof(TOut), inP.Name);

            var outBody = Rewrite<TIn, TOut>(
                inExpr.Body,
                expr => (expr is ParameterExpression) ? outP : expr
            );
            return Expression.Lambda<Func<TOut, bool>>(
                    outBody,
                    new ParameterExpression[] { outP });
        } else {
            throw new NotSupportedException();
        }
    }

    /// <summary>
    /// Rewrites the specified expression.
    /// </summary>
    /// <typeparam name="TIn">The type of the in.</typeparam>
    /// <typeparam name="TOut">The type of the out.</typeparam>
    /// <param name="exp">The exp.</param>
    /// <param name="c">The c.</param>
    /// <returns></returns>
    private static Expression Rewrite<TIn, TOut>(Expression exp, Func<Expression, Expression> c) {
        Expression clone = null;
        var be = exp as BinaryExpression;
        switch (exp.NodeType) {
            case ExpressionType.AndAlso:
                clone = Expression.AndAlso(Rewrite<TIn, TOut>(be.Left, c), Rewrite<TIn, TOut>(be.Right, c), be.Method);
                break;
            case ExpressionType.OrElse:
                clone = Expression.OrElse(Rewrite<TIn, TOut>(be.Left, c), Rewrite<TIn, TOut>(be.Right, c), be.Method);
                break;
            case ExpressionType.Equal:
                clone = Expression.Equal(Rewrite<TIn, TOut>(be.Left, c), Rewrite<TIn, TOut>(be.Right, c), be.IsLiftedToNull, be.Method);
                break;
            case ExpressionType.GreaterThan:
                clone = Expression.GreaterThan(Rewrite<TIn, TOut>(be.Left, c), Rewrite<TIn, TOut>(be.Right, c), be.IsLiftedToNull, be.Method);
                break;
            case ExpressionType.GreaterThanOrEqual:
                clone = Expression.GreaterThanOrEqual(Rewrite<TIn, TOut>(be.Left, c), Rewrite<TIn, TOut>(be.Right, c), be.IsLiftedToNull, be.Method);
                break;
            case ExpressionType.LessThan:
                clone = Expression.LessThan(Rewrite<TIn, TOut>(be.Left, c), Rewrite<TIn, TOut>(be.Right, c), be.IsLiftedToNull, be.Method);
                break;
            case ExpressionType.LessThanOrEqual:
                clone = Expression.LessThanOrEqual(Rewrite<TIn, TOut>(be.Left, c), Rewrite<TIn, TOut>(be.Right, c), be.IsLiftedToNull, be.Method);
                break;
            case ExpressionType.NotEqual:
                clone = Expression.NotEqual(Rewrite<TIn, TOut>(be.Left, c), Rewrite<TIn, TOut>(be.Right, c), be.IsLiftedToNull, be.Method);
                break;
            case ExpressionType.Not:
                var ue = exp as UnaryExpression;
                clone = Expression.Not(Rewrite<TIn, TOut>(ue.Operand, c));
                break;
            case ExpressionType.MemberAccess:
                var me = exp as MemberExpression;

                MemberInfo newMember = me.Member;
                Type newType = newMember.DeclaringType;
                if (newType == typeof(TIn)) {
                    newType = typeof(TOut);
                    MemberInfo[] members = newType.GetMember(me.Member.Name);
                    if (members.Length == 1) {
                        newMember = members[0];
                    } else {
                        throw new NotSupportedException();
                    }
                }
                clone = Expression.MakeMemberAccess(Rewrite<TIn, TOut>(me.Expression, c), newMember);
                break;
            case ExpressionType.Constant:
                var ce = exp as ConstantExpression;
                clone = Expression.Constant(ce.Value);
                break;
            case ExpressionType.Parameter:
                var pe = exp as ParameterExpression;
                Type peNewType = pe.Type;
                if (peNewType == typeof(TIn)) {
                    peNewType = typeof(TOut);
                }
                clone = Expression.Parameter(peNewType, pe.Name);
                break;
            case ExpressionType.Call:
                MethodCallExpression mce = exp as MethodCallExpression;
                if (mce.Arguments != null && mce.Arguments.Count > 0) {
                    List<Expression> expressionList = new List<Expression>();
                    foreach (Expression expression in mce.Arguments) {
                        expressionList.Add(Rewrite<TIn, TOut>(expression, c));
                    }
                    clone = Expression.Call(Rewrite<TIn, TOut>(mce.Object, c), mce.Method, expressionList.ToArray());
                } else {
                    clone = Expression.Call(Rewrite<TIn, TOut>(mce.Object, c), mce.Method);
                }
                break;
            case ExpressionType.Invoke:
                InvocationExpression ie = exp as InvocationExpression;
                List<Expression> arguments = new List<Expression>();
                foreach (Expression expression in ie.Arguments) {
                    arguments.Add(Rewrite<TIn, TOut>(expression, c));
                }
                clone = Rewrite<TIn, TOut>(ie.Expression, c);
                //clone = Expression.Invoke(Rewrite<TIn, TOut>(ie.Expression, c), arguments);
                break;
            case ExpressionType.Convert:
                var ue2 = exp as UnaryExpression;
                //clone = Expression.Not(Rewrite<TIn, TOut>(ue2.Operand, c));
                clone = Expression.Convert(ue2.Operand, ue2.Type, ue2.Method);
                break;
            default:
                throw new NotImplementedException(exp.NodeType.ToString());
        }
        return c(clone);
    }
}
于 2012-08-16T11:45:46.987 に答える