6

通常は次のようなwhere句に含まれるLinqの条件を含むFilterオブジェクトを作成する場合:

 var myFilterObject = FilterFactory.GetBlank();
 myFilterObject.AddCondition("Salary", "lessThan", "40000");

 var myResult = myRepository.GetEmployees(myFilterObject);

大きなcaseステートメントを使用せずに、Linqフィールドをフィールド名にどのように一致させますか?

 return from e in db.Employee
        where e.Salary < 40000
        select new IList<EmployeeViewModel> { Name= e.name, Salary= e.Salary };

必要なレコードのみをプルするように、フィルタリングを指定するオブジェクトをリポジトリに送信する必要があると思います。Linqはプリコンパイルしないと思います(カスタマイズされたデリゲートと関数を作成しない限り)。したがって、フィルタリングするフィールドを動的に指定できるはずです。

ある種のExpandoオブジェクトのようなe["Salary"]のようなことができたらいいのにと思います。

4

3 に答える 3

12

次のように、式を手動で作成できます。

var eParam = Expression.Parameter(typeof(Employee), "e");

var comparison = Expression.Lambda(
    Expression.LessThan(
        Expression.Property(eParam, "Salary"),
        Expression.Constant(40000)),
    eParam);

return from e in db.Employee.Where(comparison)
       select new EmployeeViewModel { Name = e.name, Salary = e.Salary };
于 2010-03-23T21:38:25.637 に答える
9

LinqtoSQLの例の動的クエリをご覧になることをお勧めします。これを使用して、「プレーンテキスト」に条件を書き込むことができます。例:

var employees = db.Employee.Where("Salary < 40000").Select(...);

明確にするために:これらの拡張機能は、基本的に、ラムダを介して通常作成する文字列から同じ式ツリーを構築するため、データベースに対して生のSQLを書き込むことと同じではありません。from x in y唯一の欠点は、クエリ理解構文(など)を使用できないことです。

于 2010-03-23T03:04:33.923 に答える
4

私はこのパーティーにかなり遅れていることに気づきましたが、サポートが不十分で、(せいぜい)使用するのが危険であることがわかったDynamicLINQを使用せずに、これを満たすと信じるコードをいくつか作成しました。

    /// <summary>
    ///     A method to create an expression dynamically given a generic entity, and a propertyName, operator and value.
    /// </summary>
    /// <typeparam name="TEntity">
    ///     The class to create the expression for. Most commonly an entity framework entity that is used
    ///     for a DbSet.
    /// </typeparam>
    /// <param name="propertyName">The string value of the property.</param>
    /// <param name="op">An enumeration type with all the possible operations we want to support.</param>
    /// <param name="value">A string representation of the value.</param>
    /// <param name="valueType">The underlying type of the value</param>
    /// <returns>An expression that can be used for querying data sets</returns>
    private static Expression<Func<TEntity, bool>> CreateDynamicExpression<TEntity>(string propertyName,
        Operator op, string value, Type valueType)
    {
        Type type = typeof(TEntity);
        object asType = AsType(value, valueType);
        var p = Expression.Parameter(type, "x");
        var property = Expression.Property(p, propertyName);
        MethodInfo method;
        Expression q;

        switch (op)
        {
            case Operator.Gt:
                q = Expression.GreaterThan(property, Expression.Constant(asType));
                break;
            case Operator.Lt:
                q = Expression.LessThan(property, Expression.Constant(asType));
                break;
            case Operator.Eq:
                q = Expression.Equal(property, Expression.Constant(asType));
                break;
            case Operator.Le:
                q = Expression.LessThanOrEqual(property, Expression.Constant(asType));
                break;
            case Operator.Ge:
                q = Expression.GreaterThanOrEqual(property, Expression.Constant(asType));
                break;
            case Operator.Ne:
                q = Expression.NotEqual(property, Expression.Constant(asType));
                break;
            case Operator.Contains:
                method = typeof(string).GetMethod("Contains", new[] {typeof(string)});
                q = Expression.Call(property, method ?? throw new InvalidOperationException(),
                    Expression.Constant(asType, typeof(string)));
                break;
            case Operator.StartsWith:
                method = typeof(string).GetMethod("StartsWith", new[] {typeof(string)});
                q = Expression.Call(property, method ?? throw new InvalidOperationException(),
                    Expression.Constant(asType, typeof(string)));
                break;
            case Operator.EndsWith:
                method = typeof(string).GetMethod("EndsWith", new[] {typeof(string)});
                q = Expression.Call(property, method ?? throw new InvalidOperationException(),
                    Expression.Constant(asType, typeof(string)));
                break;
            default:
                throw new ArgumentOutOfRangeException(nameof(op), op, null);
        }

        return Expression.Lambda<Func<TEntity, bool>>(q, p);
    }

    /// <summary>
    ///     Extract this string value as the passed in object type
    /// </summary>
    /// <param name="value">The value, as a string</param>
    /// <param name="type">The desired type</param>
    /// <returns>The value, as the specified type</returns>
    private static object AsType(string value, Type type)
    {
        //TODO: This method needs to be expanded to include all appropriate use cases
        string v = value;
        if (value.StartsWith("'") && value.EndsWith("'"))
            v = value.Substring(1, value.Length - 2);

        if (type == typeof(string))
            return v;
        if (type == typeof(DateTime))
            return DateTime.Parse(v);
        if (type == typeof(DateTime?))
            return DateTime.Parse(v);
        if (type == typeof(int))
            return int.Parse(v);
        if (type == typeof(int?)) return int.Parse(v);

        throw new ArgumentException("A filter was attempted for a field with value '" + value + "' and type '" +
                                    type + "' however this type is not currently supported");
    }

このコードは次のように使用できます。

var whereClause = CreateDynamicExpression<MyDatabaseTable>("MyFieldName",
                    Operator.Contains, "some string value",typeof(string));
var results = _db.MyDatabaseTable.Where(whereClause);
于 2018-05-04T18:23:10.820 に答える