【问题标题】:linq lambda expression for sql contains用于 sql 的 linq lambda 表达式包含
【发布时间】:2016-10-01 16:15:29
【问题描述】:

我正在使用通用存储库,如下所示:

 itemsList = (from myrow in UoW.FileRepository.Get()
 select new FileModel()
 {record_id = myrow.type_id,
  descr = myrow.descr}).ToList();});

这是 Get 方法:

 public virtual IEnumerable<TEntity> Get()
    {
        //  _aQuery = _theDbContext.Set<TEntity>();
        IEnumerable<TEntity> query = _aQuery;
        return query;
    }

如果我想创建一个类似的查询来搜索特定字段中的特定字符串,我将如何实现一个通用的 linq lambda 表达式?在我的视图模型中,我想这样称呼:

     from myrow in UoW.FileRepository.Srch(nameofFieldToSearch, searchString). 

查询看起来像这样?

   public IEnumerable<TEntity> Srch(Expression<Func<TEntity, bool>> expression)
    {
        IEnumerable<TEntity> srchList = _aQuery.ToList();
        return srchList.Where(????);

    }

感谢您的建议。

编辑----------- 我在通用存储库类中有所有查询,例如 Get 和 Srch,现在只需要知道如何在存储库类中声明查询以及如何使用我的视图模型中的搜索字符串调用它。我不确定是否就何时/何时实现和编译达成共识?我看到另一个讨论http://www.fascinatedwithsoftware.com/blog/post/2012/01/10/More-on-Expression-vs-Func-with-Entity-Framework.aspx,我在下面引用它来询问这是否与这里建议的方法相同?再次感谢。

“分析器告诉我们,LoadMyEntities 被调用了很多很多次,它占用了我们大部分 CPU 时间。下面的简单更改解决了这个问题。你能猜出原因吗?”

public IEnumerable<MyEntity> LoadMyEntities(Func<MyEntity, bool> predicate)
{return Context.MyEntities.Where(predicate);}

“参数现在是一个 Func 而不是一个表达式>。这有所不同的原因是一个表达式形式的谓词被传递给 SQL 服务器,但是一个作为 Func 传递的谓词是不是。通常情况下,您希望 SQL Server 为您做尽可能多的事情,而 Expression 将是正确的选择,但在这种情况下,我们希望在上下文中预加载整个表——即正是 Func 的作用。

  1. Where 扩展方法有两种风格。一个扩展 IQueryable 并采用 Expression 参数。另一个扩展 IEnumerable 并采用 Func。
  2. 因为“谓词”现在是一个 Func,所以使用了扩展 IEnumerable 的 Where。
  3. Entity Framework 用于构建 SQL 查询的流畅接口基于 IQueryables,而不是 IEnumerables。因此,流畅度在 Where 之前停止。传递给实体框架的语句部分只是 Context.MyEntities。
  4. 因此,Context.MyEntities 会将整个表返回到上下文。
  5. 现在使用谓词过滤整个表,并返回我们真正想要的值。
  6. 下次调用该方法时,实体框架意识到我们想要的记录已经在上下文中。 (在我的例子中,我们通过主键进行查询,而 EF 显然足够聪明,可以知道如果上下文中存在具有该 ID 的记录,它不会在数据库中找到额外的此类记录。)因为我们不不要使用 SQL Server,我们可以节省大量时间。显然,有时您不希望这样做,但在我们的情况下,这正是我们想要的。表比较小,同一个上下文被查询了几百次。

在原始版本中,谓词是一个表达式,因此编译器使用了扩展 IQueryable 的 Where。谓词因此被传递给 SQL Server,它尽职尽责地将一行返回给上下文。下次我们调用 LoadMyEntities 时,Entity Framework 不得不再次调用 SQL Server。”

【问题讨论】:

  • 查看动态 LINQ。

标签: c# linq lambda expression


【解决方案1】:

请查看msdn 存储库模式

 public virtual IEnumerable<TEntity> Get(
        Expression<Func<TEntity, bool>> filter = null,
        Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
        string includeProperties = "")
    {
        IQueryable<TEntity> query = dbSet;

        if (filter != null)
        {
            query = query.Where(filter);
        }

        foreach (var includeProperty in includeProperties.Split
            (new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
        {
            query = query.Include(includeProperty);
        }

        if (orderBy != null)
        {
            return orderBy(query).ToList();
        }
        else
        {
            return query.ToList();
        }
    }

这将提供更完整的 Generic Get 方法。

搜索你可以试试

public IEnumerable<TEntity> GlobalSearch(Expression<Func<TEntity, bool>> expression)
{
   return Get(expression);
}

DataProvider 你可以尝试这样的事情

注意这可能不是确切的实现,但会给你基本的想法,如何调用。

public List<Users> Search(List<string> userList)
{
      Expression<Func<User, bool>> expression = x=>UserList.Contains(x.UserName);

      return GlobalSearch(expression);

}

Example 的存储库模式

【讨论】:

  • 存储库模式很好,但是您在哪里创建了过滤器表达式,这是 OP 的主要挑战
  • @MrinalKamboj 我已经更新了答案,我认为这可能对如何调用有基本的了解
  • 这仍然无济于事,因为 OP 没有按预期获取 x.UserName 的类型化实体,列名可作为字符串使用
【解决方案2】:

这将是一个使用表达式树的简单实现。以下是完整的解决方案:

获取Srch 方法的表达式的方法:

Public Expression<Func<TEntity, bool>> SrchExpression(string nameofFieldToSearch, string searchString)
{
  var parameterType = Expression.Parameter(typeof(TEntity), "obj");

  var memberExpression = Expression.Property(typeof(string), nameofFieldToSearch)

 // Calls Extension method created underneath
 var filtersMethodInfo = typeof(StringExtensions).GetMethod("Contains", new[] { typeof(string), typeof(string) });

 var filtersConstantExpression = Expression.Constant(searchString, typeof(string));

 var finalExpression = Expression.Call(null, filtersMethodInfo, memberExpression, filtersConstantExpression)

 return Expression.Lambda<Func<TEntity, bool>>(finalExpression, parameterType)
}

// 为 Contains 创建一个 String 扩展方法

public static class StringExtensions
{        
    public static bool Contains(this string source, string searchString)
    {
        return source?.IndexOf(subString, StringComparison.OrdinalIgnoreCase) >= 0;
    }
}

现在您的 Srch 方法应如下所示:

public IEnumerable<TEntity> Srch(Expression<Func<TEntity, bool>> expression)
{
    Func<TEntity, bool>> func = expression.Compile();
    IEnumerable<TEntity> srchList = _aQuery.Where(o => func(o));
    return srchList;
}

【讨论】:

  • _aQuery.Where(expression).ToList() 怎么样ToList() 将实现查询。在实现之前添加过滤条件怎么样
  • 那会比较慢,因为每次都会编译,编译是很重要的操作,IEnumerable中的每个值都不能重复
  • 如果数据库包含 1000 条记录,实现将比编译花费更多时间
  • 好吧,我们在谈论不同的事情,我已经复制了 OP 的代码,他将其设为 ToList(),然后应用到 Where,但我们可以直接应用,尽管它需要在某个地方实现。检查编辑,尽管提前编译表达式对于任何类型的数据仍然很重要
  • 感谢您的回复。我从概念上理解 lambdas、表达式和 func,但实现它是我的问题。我在其他地方看到了一种方法,想知道这里的建议与该方法相比如何。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-29
  • 1970-01-01
  • 1970-01-01
  • 2011-06-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多