使用Linq的条件where子句的计算和风格最优解决方案

时间:2015-08-27 09:51:19

标签: c# linq

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

我需要使用一些条件where子句进行新的审讯。 在网上搜索我找到了一些解决方案,几乎所有解决方案都是这样的:Conditional Linq Queries

但是,我不认为它具有计算效率。 事实上,如果我有一个表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();

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

2 个答案:

答案 0 :(得分:2)

如果你刚刚使用......

var usr = context.USERS

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

然后usr是IQueryable,直到.ToList()调用(或类似)才被评估/执行。

所以回答你的问题:

  • 你的想法是正确的
  • 第二种解决方案更好
  • 至于更好的解决方案,我不确定可以做多少改进,因为Linq将“优化”任何查询。我个人更喜欢分离.Where()子句,因为我觉得它更容易阅读,ymmv。

这样的事情

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();

答案 1 :(得分:1)

使用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

警惕重用代码并能够理解操作的复杂程度是编写" performant"以这种方式编码(它仍然比编写表达式更重)。

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