【问题标题】:What's the difference between these LINQ queries?这些 LINQ 查询有什么区别?
【发布时间】:2010-03-18 10:34:27
【问题描述】:

我使用 LINQ-SQL 作为我的 DAL,然后我有一个名为 DB 的项目作为我的 BLL。然后各种应用程序访问 BLL 以从 SQL 数据库读取/写入数据。

我的 BLL 中有一张特定表的这些方法:

public IEnumerable<SystemSalesTaxList> Get_SystemSalesTaxList()
{
        return from s in db.SystemSalesTaxLists
               select s;
}

public SystemSalesTaxList Get_SystemSalesTaxList(string strSalesTaxID)
{
    return Get_SystemSalesTaxList().Where(s => s.SalesTaxID == strSalesTaxID).FirstOrDefault();
}

public SystemSalesTaxList Get_SystemSalesTaxListByZipCode(string strZipCode)
{
    return Get_SystemSalesTaxList().Where(s => s.ZipCode == strZipCode).FirstOrDefault();
}

我认为一切都非常简单。

Get_SystemSalesTaxListByZipCode 始终返回空值,即使该表中存在邮政编码。

如果我这样写方法,它会返回我想要的行:

public SystemSalesTaxList Get_SystemSalesTaxListByZipCode(string strZipCode)
{
   var salesTax = from s in db.SystemSalesTaxLists
                  where s.ZipCode == strZipCode
                  select s;

   return salesTax.FirstOrDefault();
}

为什么其他方法返回的结果不一样,因为查询应该是相同的?

请注意,当我给它一个有效的SalesTaxID 时,重载的Get_SystemSalesTaxList(string strSalesTaxID) 返回一个记录就好了。

有没有更有效的方法来编写这些“帮助”类型的类?

谢谢!

【问题讨论】:

  • 愚蠢的问题 - 你确定你将邮政编码传递给Get_SystemSalesTaxListByZipCode吗?
  • 问题出在IEnumerable&lt;T&gt; - 但我只是大声说“这可能是抱怨匈牙利符号的方式”;-p

标签: c# asp.net sql linq


【解决方案1】:

这可能是由于 LINQ 处理 IEnumerable&lt;T&gt;IQueryable&lt;T&gt; 的方式不同。

您已将Get_SystemSalesTaxList 声明为返回IEnumerable&lt;SystemSalesTaxList&gt;。这意味着,在您的第一个代码示例中,当您将 Where 运算符应用于 Get_SystemSalesTaxList 的结果时,它将被解析为 Enumerable.Where 扩展方法。 (请注意,重要的是 declared 类型。是的,在运行时 Get_SystemSalesTaxList 返回一个 IQueryable&lt;SystemSalesTaxList&gt;,但它的 declared 类型——编译器看到的——是 @ 987654327@.) Enumerable.Where 在目标序列上运行指定的 .NET 谓词。在这种情况下,它遍历由 Get_SystemSalesTaxList 返回的所有 SystemSalesTaxList 对象,生成 ZipCode 属性等于指定邮政编码字符串的对象(使用 .NET String == 运算符)。

但在上一个代码示例中,您将 Where 运算符应用于 db.SystemSalesTaxList,它被声明为类型为 IQueryable&lt;SystemSalesTaxList&gt;。因此,该示例中的 Where 运算符解析为 Queryable.Where,它将指定的谓词表达式转换为 SQL 并在数据库上运行。

因此,邮政编码方法的不同之处在于,第一个方法在 .NET 中运行 C# s.ZipCode == strZipCode 测试,而第二个方法将其转换为 SQL 查询 WHERE ZipCode = 'CA 12345'(实际上是参数化 SQL,但你明白了)。为什么这些会给出不同的结果?很难确定,但 C# == 谓词区分大小写,并且根据您的排序规则设置,SQL 可能区分大小写,也可能不区分大小写。所以我怀疑strZipCode 与数据库邮政编码不匹配,以防万一,但在第二个版本中,SQL Server 排序规则解决了这个问题。

最好的解决方案可能是将 Get_SystemSalesTaxList 的声明更改为返回IQueryable&lt;SystemSalesTaxList&gt;。这样做的主要好处是它意味着在 Get_SystemSalesTaxList 上构建的查询将在数据库端执行。目前,您的方法正在撤回数据库表中的 EVERYTHING 并在客户端对其进行过滤。更改声明将使您的查询转换为 SQL,它们将更有效地运行,并有望解决您的邮政编码问题。

【讨论】:

  • 对我来说很有意义,并且正是我在发布问题时希望得到的那种答案!谢谢。
【解决方案2】:

这里真正的问题是使用IEnumerable&lt;T&gt;,它破坏了查询的“组合”;这有两个效果:

  • 您每次都在阅读所有(或至少超过您需要的)表格,即使您只要求一行
  • 您正在运行 LINQ-to-Objects 规则,因此需要区分大小写

相反,您希望在数据层中使用 IQueryable&lt;T&gt;,允许您根据需要将多个查询与其他 WhereOrderBySkipTake 等组合起来,并让它构建要匹配的 TSQL(并使用您的数据库的区分大小写规则)。

有没有更有效的方法来编写这些“帮助”类型的类?

为了更高效(要调试的代码更少,不会流式传输整个表,更好地使用标识映射来缩短额外的查找(通过FirstOrDefault 等)):

public IEnumerable<SystemSalesTaxList> Get_SystemSalesTaxList()
{
    return db.SystemSalesTaxLists;
}

public SystemSalesTaxList Get_SystemSalesTaxList(string salesTaxID)
{
    return db.SystemSalesTaxLists.FirstOrDefault(s => s.SalesTaxID==salesTaxID);
}

public SystemSalesTaxList Get_SystemSalesTaxListByZipCode(string zipCode)
{
    return db.SystemSalesTaxLists.FirstOrDefault(s => s.ZipCode == zipCode);
}

【讨论】:

  • 虽然在.NET 3.5/3.5SP1/4.0 之间Where(predicate).FirstOrDefault()FirstOrDefault(predicate) 之间的区别另请参阅我的注释 (stackoverflow.com/questions/2469816/…)
  • 谢谢,我的问题不是一个而是两个很好的答案!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-28
  • 1970-01-01
  • 2010-12-19
  • 2012-03-29
相关资源
最近更新 更多