Linq和SQL查询比较

时间:2011-04-04 07:58:16

标签: asp.net linq linq-to-entities

我有这个SQL查询:

SELECT Sum(ABS([Minimum Installment])) AS SumOfMonthlyPayments FROM tblAccount 
INNER JOIN tblAccountOwner ON tblAccount.[Creditor Registry ID] = tblAccountOwner.
[Creditor Registry ID] AND tblAccount.[Account No] = tblAccountOwner.[Account No] 
WHERE (tblAccountOwner.[Account Owner Registry ID] = 731752693037116688)
 AND (tblAccount.[Account Type] NOT IN 
('CA00', 'CA01', 'CA03', 'CA04', 'CA02', 'PA00', 'PA01', 'PA02', 'PA03', 'PA04'))
AND (DATEDIFF(mm, tblAccount.[State Change Date], GETDATE()) <= 
4 OR tblAccount.[State Change Date] IS NULL)
AND ((tblAccount.[Account Type] IN ('CL10','CL11','PL10','PL11')) OR
CONTAINS(tblAccount.[Account Type], 'Mortgage')) AND (tblAccount.[Account Status ID] <> 999)   

我创建了一个Linq查询:

var ownerRegistryId = 731752693037116688;
var excludeTypes = new[]
{
    "CA00", "CA01", "CA03", "CA04", "CA02",
    "PA00", "PA01", "PA02", "PA03", "PA04"
};

var maxStateChangeMonth = 4;
var excludeStatusId = 999;
var includeMortgage = new[] { "CL10", "CL11", "PL10", "PL11" };

var sum = (
    from account in context.Accounts
    from owner in account.AccountOwners
    where owner.AccountOwnerRegistryId == ownerRegistryId
    where !excludeTypes.Contains(account.AccountType)
    where account.StateChangeDate == null ||
       (account.StateChangeDate.Month - DateTime.Now.Month)
            <= maxStateChangeMonth
    where includeMortgage.Contains(account.AccountType) ||
        account.AccountType.Contains("Mortgage")
    where account.AccountStatusId != excludeStatusId
    select account.MinimumInstallment).ToList()
    .Sum(minimumInstallment =>
        Math.Abs((decimal)(minimumInstallment)));

return sum;

它们是相同还是相同?我在db中没有记录,所以我不能确认它们是否相等。在SQL中有方括号(),但在Linq中我没有使用它们,所以可以吗?

请建议。

3 个答案:

答案 0 :(得分:1)

我们不可能对此说些什么,因为您没有向我们展示DBML。模型和数据库之间映射的实际定义对于能够看到它的执行方式非常重要。

但在你将DBML添加到你的问题之前:我们不是来做你的工作,所以这里有两个提示,以确定它们是否相同:

  1. 在数据库中插入数据并运行查询。
  2. 使用SQL事件探查器,查看LINQ提供程序在幕后执行的查询。
  3. 如果你有更具体的要求,我们非常乐意提供帮助。

答案 1 :(得分:1)

如有必要,括号将由LINQ提供商生成 检查LINQ查询是否等于初始SQL查询的最简单方法是将其记录为@Atanas Korchev建议的内容。
但是,如果您使用的是Entity Framework,则没有Log属性,但您可以尝试将查询转换为ObjectQuery,然后调用ToTraceString方法:
string sqlQuery = (sum as ObjectQuery).ToTraceString();
UPD 。 ToTraceString方法需要一个ObjectQuery实例进行跟踪,而ToList()调用已经执行实现,因此无需跟踪任何内容。这是更新的代码:

var sum = (
from account in context.Accounts
from owner in account.AccountOwners
where owner.AccountOwnerRegistryId == ownerRegistryId
where !excludeTypes.Contains(account.AccountType)
where account.StateChangeDate == null ||
   (account.StateChangeDate.Month - DateTime.Now.Month)
        <= maxStateChangeMonth
where includeMortgage.Contains(account.AccountType) ||
    account.AccountType.Contains("Mortgage")
where account.AccountStatusId != excludeStatusId
select account.MinimumInstallment);
string sqlQuery = (sum as ObjectQuery).ToTraceString();  

请注意,此代码不会执行实际查询,仅可用于测试目的。 如果您对准备生产日志记录实施感兴趣,请查看this article

答案 2 :(得分:0)

可能存在性能差异:

SQL查询直接从数据库服务器向执行查询的客户端返回一个数字(SELECT Sum...)。

在您的LINQ查询中,您之间有一个贪婪的运算符(.ToList()):

var sum = (...
    ...
    select account.MinimumInstallment).ToList()
    .Sum(minimumInstallment =>
        Math.Abs((decimal)(minimumInstallment)));

这意味着SQL服务器上的查询不包含.Sum操作。查询返回(可能很长?)MinimumInstallments列表。然后在客户端的内存中执行.Sum操作。

如此有效地在.ToList()之后从LINQ切换到实体到LINQ到对象。

顺便说一句:您能否检查previous question here中的最后一个提案,该提案会避免.ToList()此查询(如果提案可行),因此会更接近SQL语句。