【问题标题】:LINQ Use "like" instead of "(( NVL(INSTR(x, y), 0) ) = 1)"LINQ 使用 "like" 而不是 "(( NVL(INSTR(x, y), 0) ) = 1)"
【发布时间】:2018-11-21 20:27:52
【问题描述】:

使用 .Contains()/.StartsWith()/.EndsWith() 时,生成的 SQL 如下所示:

(( NVL(INSTR(x, y), 0) ) = 1)

有没有办法代替它:

LIKE 'x%' or '%x%' or '%x'

因为在查询的执行计划中这两者之间存在巨大的成本差异(44 000 vs 30)。

【问题讨论】:

  • 这很大程度上取决于您使用的 Oracle 提供程序。是哪一个?
  • 我们使用的是 Oracle 11G
  • 不,那是数据库,不是 EF 提供者
  • 提供者列表here 以便帮助您澄清这一点。也许其中一个会敲响警钟并帮助澄清。
  • 我认为x LIKE '%y'x LIKE '%y%' 在这种情况下不会比使用INSTR(x,y) 好得多-x LIKE 'y%' 肯定会只要有问题的列被索引。所以真正的问题是StartsWith()

标签: c# .net oracle linq


【解决方案1】:

当我环顾四周时,我发现LIKE operator in LINQ 有几个很好的例子来说明如何做到这一点。我已经测试了下面来自上面链接的那个

这是 adobrzyc 发布的使用 Like 和 lambda 的扩展

    public static class LinqEx
    {
        private static readonly MethodInfo ContainsMethod = typeof(string).GetMethod("Contains");
        private static readonly MethodInfo StartsWithMethod = typeof(string).GetMethod("StartsWith", new[] { typeof(string) });
        private static readonly MethodInfo EndsWithMethod = typeof(string).GetMethod("EndsWith", new[] { typeof(string) });

        public static Expression<Func<TSource, bool>> LikeExpression<TSource, TMember>(Expression<Func<TSource, TMember>> property, string value)
        {
            var param = Expression.Parameter(typeof(TSource), "t");
            var propertyInfo = GetPropertyInfo(property);
            var member = Expression.Property(param, propertyInfo.Name);

            var startWith = value.StartsWith("%");
            var endsWith = value.EndsWith("%");

            if (startWith)
                value = value.Remove(0, 1);

            if (endsWith)
                value = value.Remove(value.Length - 1, 1);

            var constant = Expression.Constant(value);
            Expression exp;

            if (endsWith && startWith)
            {
                exp = Expression.Call(member, ContainsMethod, constant);
            }
            else if (startWith)
            {
                exp = Expression.Call(member, EndsWithMethod, constant);
            }
            else if (endsWith)
            {
                exp = Expression.Call(member, StartsWithMethod, constant);
            }
            else
            {
                exp = Expression.Equal(member, constant);
            }

            return Expression.Lambda<Func<TSource, bool>>(exp, param);
        }

        public static IQueryable<TSource> Like<TSource, TMember>(this IQueryable<TSource> source, Expression<Func<TSource, TMember>> parameter, string value)
        {
            return source.Where(LikeExpression(parameter, value));
        }

        private static PropertyInfo GetPropertyInfo(Expression expression)
        {
            var lambda = expression as LambdaExpression;
            if (lambda == null)
                throw new ArgumentNullException("expression");

            MemberExpression memberExpr = null;

            switch (lambda.Body.NodeType)
            {
                case ExpressionType.Convert:
                    memberExpr = ((UnaryExpression)lambda.Body).Operand as MemberExpression;
                    break;
                case ExpressionType.MemberAccess:
                    memberExpr = lambda.Body as MemberExpression;
                    break;
            }

            if (memberExpr == null)
                throw new InvalidOperationException("Specified expression is invalid. Unable to determine property info from expression.");


            var output = memberExpr.Member as PropertyInfo;

            if (output == null)
                throw new InvalidOperationException("Specified expression is invalid. Unable to determine property info from expression.");

            return output;
        }
    }

要使用它,您只需在要放置 Contains 函数的位置添加 Like 函数。您可以在下面查看示例

            using (CustomerEntities customerContext = new CustomerEntities())
            {
                IQueryable<Customer> customer = customerContext.Customer.Like(x => x.psn, "%1%");    
            }

这将创建一个看起来像这样的 sql 查询。

SELECT 
[Extent1].[psn] AS [psn]
FROM [dbo].[Customer] AS [Extent1]
WHERE [Extent1].[psn] LIKE '%1%'

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-02
    • 2016-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多