【问题标题】:How can I make this LINQ to SQL where clause with conditions faster?如何使这个 LINQ to SQL where 条件的子句更快?
【发布时间】:2021-01-25 20:28:39
【问题描述】:

我有以下 LINQ to SQL 查询,但我想知道在将它们添加到 where 子句之前是否有更快的方法来验证来自 post 操作的数据?例如:

bookFilter = Informations coming from the post action

int count = from b in _libraryContext.Book
            join ba in _libraryContext.BookAuthor
            on b.Id equals ba.BookId
            where (!string.IsNullOrWhiteSpace(bookFilter.Name) ? 
            b.Name.Contains(bookFilter.Name.ToUpper()) : 1 == 1 )
            where (!string.IsNullOrWhiteSpace(bookFilter.Decription) ? 
            b.Description.Contains(bookFilter.Description.ToUpper()) : 1 == 1)
            where (bookFilter.BookId > 0 ? ba.BookId == bookFilter.BookId : 1 == 1)

return count;

【问题讨论】:

  • 在这种特殊情况下,您对“更好”的定义是什么?
  • 让我们说更干净更快捷的方式?
  • “干净”是主观的,可以基于意见。但是,如果您谈论的是可以客观衡量的性能,您应该更新您的问题以指定您想要的。
  • @Zer0 我根据您的评论更新了标题。谢谢
  • @Kivo 这样的包罗万象的查询在 SQL 中是一种不好的做法。但在 LINQ 中根本不需要它们,因为您可以根据需要链接 .Where() 调用

标签: c# linq linq-to-sql


【解决方案1】:

我从来没有经常使用这种类型的语法,所以我确定你是否可以这样做,但你当然可以使用 LINQ 来做到这一点,并像这样逐步构建你的查询:

var query = _libraryContext.Set<Book>();

if(!string.IsNullOrWhiteSpace(bookFilter.Name))
{
    query = query.Where(x => x.Name.Contains(bookFilter.Name.ToUpper()));
}

if(!string.IsNullOrWhiteSpace(bookFilter.Description))
{
    query = query.Where(x => x.Description.Contains(bookFilter.Description.ToUpper()));
}

if(bookFilter.BookId > 0)
{
    query = query.Where(x => x.BookId == bookFilter.Id);
}

return query.Count();

注意:这里我省略了 JOIN,因为它似乎没有必要,但如果你需要,当然也可以使用这种语法进行连接。

【讨论】:

  • 我正在寻找 Linq to SQL 方法,而不是 lambda 方法
  • @Kivo LINQ 是 lambdas,最初的尝试是不应该使用的不良做法,并且需要编译提示以避免性能问题
  • @PanagiotisKanavos 连接在查询表达式中通常要简单得多。使用 lambdas 表达式是地狱,难以调试和阅读
  • @Kivo 这不是查询的内容。没有什么能强迫你只使用一种或另一种形式。所有查询都是IQueryable 并返回IQueryable。您可以从查询表单中的联接开始,并根据需要添加 .Where() 调用
  • @PanagiotisKanavos 这确实是个好主意!谢谢你:)
【解决方案2】:

您已接受@Akinzekeel 上面提供的解决方案。但是,如果您尝试使用单个 LINQ 查询,我会选择以下解决方案:

bookFilter = Informations coming from the post action

请注意这里 bookFilter 必须是 IQueryable!

int count = from b in _libraryContext.Book
            join ba in _libraryContext.BookAuthor
            on b.Id equals ba.BookId
            where (b.Name.Contains(bookFilter.Name.ToUpper()) || string.IsNullOrWhiteSpace(bookFilter.Name)) && 
            (b.Description.Contains(bookFilter.Description.ToUpper()) || string.IsNullOrWhiteSpace(bookFilter.Decription)) &&
            (ba.BookId == bookFilter.BookId || bookFilter.BookId == 0 )

return count;

如果您在 SQL Profiler 中跟踪上述代码,您将看到这将生成一个 SQL 查询;类似于(OR IS NULL) 的条件。

【讨论】:

    【解决方案3】:

    在 SQL 中,您可以使用 COALESCE 来默认忽略参数——如下所示:

    SELECT *
    FROM book b
    JOIN BookAuthor ba on b.id = ba.Bookid
    WHERE COALESCE(UPPER(name), UPPER(b.name)) = UPPER(b.name)
      AND COALESCE(UPPER(description), UPPER(b.description)) = UPPER(b.description)
      AND COALESCE(bookid, b.book.id) = b.bookid 
    

    推荐的模式是将类似的东西放在 SP 中,然后调用 SP。

    【讨论】:

    • 我对此表示反对,因为问题是关于 LINQ to SQL,而不是 SQL。
    • 我将受到声誉的打击,因为我相信很多人提出这个问题最终会使用这段代码来解决他们的问题。
    猜你喜欢
    • 2012-05-06
    • 1970-01-01
    • 1970-01-01
    • 2015-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-21
    相关资源
    最近更新 更多