使用Linq的条件where子句的计算和文体最优解

本文关键字:文体最 计算 子句 Linq 条件 where 使用 | 更新日期: 2023-09-27 18:10:00

我第一次使用Linq with为我的新MVC项目。直到现在我还没有问题,但现在我卡住了。

我需要用一些条件where子句做一个新的询问。在网上搜索,我找到了一些解决方案,几乎都是这样的:条件Linq查询。

但是,我不认为它是计算效率高的。实际上,例如,如果我有一个表USERS和两个不同的过滤器NAME和PASSWORD,我将执行如下操作:

var usr = context.USERS.Select(u => u).ToList();

提取所有表数据,然后过滤结果:

if (!string.IsNullOrWhiteSpace(name))
    usr = usr.Where(u => u.NAME == name);
if (!string.IsNullOrWhiteSpace(password))
    usr = usr.Where(u => u.PASSWORD == password);

唯一可以正常工作的方法是框架将其转换为单个SQL命令。但是通过调试,我们似乎首先获得了一个List,然后在另一个步骤中对List进行了过滤。

所以我想这样做:

var usr = context.USERS.Select(u => u)
                       .Where(u => 
                             ((!string.IsNullOrWhiteSpace(name)) ? u.NAME == name : true) 
                             && 
                             ((!string.IsNullOrWhiteSpace(password)) ? u.PASSWORD == password : true))
                       .ToList();

现在,它似乎在一次射击中全部执行。

我想知道我的想法是否正确,第二个解决方案是否真的更好,以及是否有更好的解决方案。

当我尝试更新表时,如果我需要更新特定的行,也会发生类似的问题。我会试着更好地解释……总是谈到前面的例子,如果我需要更新由ID标识的特定USERS行,我可以这样做:

var user = context.USERS.Where(u => (u.ID == 1)).FirstOrDefault();
if (!string.IsNullOrWhiteSpace(name))
    user.NAME == name;
if (!string.IsNullOrWhiteSpace(password))
    user.PASSWORD == password;
context.SaveChanges();

即使在这种情况下,执行也分为两个步骤。

使用Linq的条件where子句的计算和文体最优解

如果你只是使用…

var usr = context.USERS

var usr = context.USERS.Select(u => u).Where(u => u.NAME == name)

那么usr是可查询的,直到调用。tolist()(或类似)才被计算/执行。

所以回答你的问题:

  • 你的想法是正确的
  • 第二个解决方案更好
  • 作为一个更好的解决方案,我不确定有很多改进,可以做Linq将"优化"任何查询。我个人更喜欢分开。where()子句,因为我觉得这样更容易阅读,嗯。

所以像这样的

var usr = context.USERS.Select(u => u);    
if (!string.IsNullOrWhiteSpace(name))
    usr = usr.Where(u => u.NAME == name);    
if (!string.IsNullOrWhiteSpace(password))
    usr = usr.Where(u => u.PASSWORD == password);
return usr.ToList();

使用ToList()或FirstOrDefault()将从上下文中加载实体。这意味着,在调用这些扩展之前,您可以继续使用实例化的IQueriables,而无需查询数据库。你甚至可以传递它们并在其他方法中使用它们(只是要注意不要丢弃你的上下文或加载已经在其他上下文中加载的实体)。

正确的做法是

var result = context.USERS.Where(u => 
    (!string.IsNullOrWhiteSpace(name)|| u.NAME == name) 
    && 
    (!string.IsNullOrWhiteSpace(password)|| u.PASSWORD == password));

另外,@James Sinclair回答的方式更可读,我建议你尽可能多地这样编码,因为它还允许在另一个方法中移动该代码,并添加尽可能多的过滤器。

如果你有一个未知数量的过滤器,你也可以使用表达式树,虽然通常较慢,但它提供了一种很好的动态方式来查询数据库,而不会破坏LINQ to SQL的一般安全性。

https://msdn.microsoft.com/en-us/library/bb397951.aspx

要小心重用你的代码,并且能够理解一个操作有多复杂,这是用这种方式编写"高性能"代码的基础(它仍然比写表达式要重)。

无论如何,作为一般规则,记住所有LINQ to SQL方法只会转换为SQL基本方法(所以没有带参数或其他奇怪东西的构造函数)