这些LINQ查询之间有什么区别?

时间:2010-03-18 10:34:27

标签: c# asp.net sql linq

我使用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();
}

为什么其他方法不会返回相同的内容,因为查询应该相同?

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

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

谢谢!

2 个答案:

答案 0 :(得分:7)

这可能取决于LINQ处理IEnumerable<T>IQueryable<T>的不同方式。

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

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

因此,邮政编码方法的不同之处在于,第一个在.NET中运行C#s.ZipCode == strZipCode测试,第二个将其转换为SQL查询WHERE ZipCode = 'CA 12345'(参数化SQL确实但你得到了这个想法)。为什么这些会产生不同的结果?很难确定,但C#==谓词区分大小写,并且根据您的排序规则设置,SQL可能区分大小写,也可能不区分大小写。所以我怀疑strZipCode与数据库邮政编码的情况不符,但在第二版中,SQL Server整理正在平滑这一点。

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

答案 1 :(得分:1)

这里真正的问题是IEnumerable<T>的使用,它打破了查询的“组合”;这有两个影响:

  • 你每次都在阅读你的桌子上的所有(或者至少比你需要的更多),即使你要求一排
  • 您正在运行LINQ-to-Objects规则,因此区分大小写适用

相反,您希望在数据层中使用IQueryable<T>,允许您将多个查询与其他WhereOrderBySkip,{{1}合并根据需要使用它,并使它构建匹配的TSQL(并使用db的区分大小写规则)。

  

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

为了更高效(更少的代码进行调试,不会流式传输整个表,更好地使用身份映射来短路其他查找(通过Take等)):

FirstOrDefault