【问题标题】:Linq and SQL query comparisonLinq 和 SQL 查询比较
【发布时间】:2011-04-04 07:58:16
【问题描述】:

我有这个 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;

它们是否相等/相同?我在数据库中没有记录,所以我无法确认它们是否相等。在 SQL 中有括号(),但在 Linq 中我没有使用它们,可以吗?

请提出建议。

【问题讨论】:

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


    【解决方案1】:

    我们无法对此发表任何评论,因为您没有向我们展示 DBML。模型和数据库之间映射的实际定义对于能够看到它是如何执行的很重要。

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

    1. 在您的数据库中插入数据并运行查询。
    2. 使用 SQL 分析器并查看您的 LINQ 提供程序在幕后执行了哪些查询。

    如果您有更具体的要求,我们将非常乐意提供帮助。

    【讨论】:

    • 嗨史蒂文:我只想知道如果我正确翻译了 SQL?
    • @DotnetSparrow:我知道你想要,但正如我在回答中所说:我们不能告诉你,因为缺少信息,即使没有:代码 sn-p 也是大的。你必须自己弄清楚。希望我和其他人的建议能帮助您找到问题的答案。
    【解决方案2】:

    如有必要,括号将由 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

    【讨论】:

    • 和@Atanas:我在 MVC 应用程序中工作,所以那里可以使用跟踪,或者可以访问 context.log?
    • 嗨@Devart:当我使用 TraceString 时出现此错误:无法通过引用转换、装箱转换、拆箱转换、包装转换将类型“十进制”转换为“System.Data.Objects.ObjectQuery” , 或空类型转换
    • 您已从查询中删除了 Math.abs 部分?
    • @DotnetSparrow,它不参与 SQL 查询。 Abs 和 Sum 函数应用于从数据库获取并在 ToList() 调用中具体化的 .NET 对象。从您之前的问题来看,这是您所期望的行为,因为它不会给出将空值转换为十进制的错误。
    【解决方案3】:

    可能存在性能差异:

    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 语句。

    【讨论】:

    • @Saluma:我试过了,但我还是遇到了同样的错误,所以我使用了 tolist 并且它消失了。
    • @DotnetSparrow:我明白了,上一个问题有一个新的编辑。
    猜你喜欢
    • 2015-08-30
    • 2013-01-13
    • 2020-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-21
    • 1970-01-01
    相关资源
    最近更新 更多