首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何动态使用SqlFunctions.PatIndex

如何动态使用SqlFunctions.PatIndex
EN

Stack Overflow用户
提问于 2013-07-05 17:50:08
回答 1查看 1.4K关注 0票数 2

我需要在表达式中使用SqlFunctions.PatIndex。

代码语言:javascript
复制
Func<IQueryable<T>, KendoFilterDescription, IQueryable<T>> appendFilter =
                (filteredData, filter) => filteredData.Where(String.Format("System.Data.Objects.SqlClient.SqlFunctions.PatIndex(\"@0\", {0})", filter.Field), ParsePropertyValue(filter));

但我得到了一个例外:No property or field 'System' exists in type 'RecordListItem'

如何使用这个函数?

EN

回答 1

Stack Overflow用户

发布于 2013-07-14 14:02:23

由于代码示例中的表达式很长,可能很难看到,但"Where“子句似乎包含一个错误,因为它不是一个可以简化为Func<T, bool>的表达式。

我假设这就是为什么您要得到一个编译器错误。如果没有更多关于KendoFilterDescription是什么、ParsePropertyValue做了什么以及您试图在使用PatIndex上筛选什么的信息,就很难为您提供一个好的答案。

因此,现在我将尝试一个疯狂的猜测:

  1. 您正在尝试使用一个IQueryable表达式来筛选PatIndex。
  2. 如果求值的PatIndex表达式不返回0,则"Where“应该计算为true,因此结果中包含了记录。
  3. 您希望stringPattern参数使PatIndex表达式等于ParsePropertyValue(filter)的返回值,即要匹配的模式。
  4. 您希望PatIndex表达式的PatIndex参数等于名称为filter.FieldT的属性或字段的值。

因此,作为一个例子,让我们以一个具有属性FirstName和LastName的类Person (T)为例。假设您希望筛选包含特定短语的FirstName,则需要构建如下表达式:

代码语言:javascript
复制
Func<string, string> BuildContainsPattern = phrase => string.Format("%{0}%", phrase);
Func<IQueryable<Person>, string, IQueryable<Person>> whereFirstNameContains =
            (data, phrase) => data.Where(p => SqlFunctions.PatIndex(BuildContainsPattern(phrase), p.FirstName) > 0);

假设这(基本上)是正确的。我们需要一些构建块,这使得我们能够构建一个可以传递给Expression<Func<T, bool>>Where子句的IQueryable<T>

好吧,那么最困难的部分是。下面的BuildFilterExpression函数可以为我们构建这个表达式,前提是我们为它提供(1)作为PatIndex函数的第一个参数的stringPattern,以及(2)我们希望用作PatIndex函数的第二个参数的实体类型T上的属性的名称。

因此,如果我关于ParsePropertyValue(filter)filter.Field所代表的内容的假设是正确的,那么下面的代码应该使用过滤器提供的设置进行筛选。

代码语言:javascript
复制
using System;
using System.Linq;
using System.Reflection;
using System.Data.Objects.SqlClient;
using System.Linq.Expressions;

public class FilterDescription
{
    public enum FilterPatternType
    {
        Contains = 1,
        Range = 2, // [^0-9]
    }
    public string Field { get; set; }
    public string FilterPhrase { get; set; }
    public FilterPatternType PatternType { get; set; }
}

public static class FilterBuilder
{
    private static readonly MethodInfo PatIndexMethod = typeof(SqlFunctions).GetMethod("PatIndex");
    private static readonly ConstantExpression ValueZero = Expression.Constant(0, typeof(int?));

    public static string ParsePropertyValue(FilterDescription filter)
    {
        switch (filter.PatternType)
        {
            case FilterDescription.FilterPatternType.Contains:
                return string.Format("%{0}%", filter.FilterPhrase);
            case FilterDescription.FilterPatternType.Range:
                return string.Format("[^{0}]", filter.FilterPhrase);
            default:
                throw new InvalidOperationException("Pattern type not supported");
        }
    }

    public static Expression<Func<TEntity, bool>> BuildFilterExpression<TEntity>(string patternString, string targetProperty)
    {
        var patternStringArg = Expression.Constant(patternString);
        var entityType = Expression.Parameter(typeof(TEntity), "item");
        var targetPropertyArg = Expression.PropertyOrField(entityType, targetProperty);

        MethodCallExpression patIndexCall = Expression.Call(PatIndexMethod, patternStringArg, targetPropertyArg);

        var isGreaterThanZero = Expression.GreaterThan(patIndexCall, ValueZero);

        return Expression.Lambda<Func<TEntity, bool>>(isGreaterThanZero, entityType);
    }

    public static Expression<Func<TEntity, bool>> BuildFilterExpression<TEntity>(FilterDescription filter)
    {
        var pattern = ParsePropertyValue(filter);
        return BuildFilterExpression<TEntity>(pattern, filter.Field);
    }

    public static IQueryable<TEntity> Filter<TEntity>(this IQueryable<TEntity> toFilter, FilterDescription filter)
    {
        return toFilter.Where(BuildFilterExpression<TEntity>(filter));
    }
}

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }
}

class Program
{
    private static IQueryable<Person> GetPersons()
    {
        return (IQueryable<Person>)null; // use your own data.
    }

    public static void Main(params string[] args)
    {
        var filter = new FilterDescription() 
        { 
            PatternType = FilterDescription.FilterPatternType.Contains,
            Field = "FirstName",
            FilterPhrase = "ed"
        };
        var filtered = GetPersons().Filter(filter);
    }
}

显然,我可能完全搞错了我的胡思乱想,但我想你会改进你对你努力达到的目标的描述。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17494442

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档