Linq to SQL - 使用多个连接,求和,分组查询

时间:2017-10-31 13:42:25

标签: sql linq linq-to-sql

我有以下查询,我想将其翻译为linq。

SELECT
SUM(Credits.CreditAmount)
,Transactions.Id
,Person.FullName
,Person.Id
FROM
Person
JOIN
Transactions
ON Person.AccountId = Transactions.AccountId
JOIN Credits
ON Transactions.Id = Credits.TransactionId
WHERE
Person.Type = 'AccountHolder'
AND Person.Status = 'Active'
AND Transactions.CancelledDate IS NULL
AND Credits.CancelledDate IS NULL
GROUP BY Transactions.AccountId, Person.FullName, Person.Id
HAVING SUM(Credits.CreditAmount) > 20

这就是我想出的。它是一个绝对的猪......它生成的SQL必定是糟糕的。

var query = from p in Person
            join t in Transactions
            on p.AccountId equalas t.AccountId
            join c in Credits
            on t.TransactionId = c.TransactionId
            where p.Status == "Active" &&
            p.Type = "AccountHolder" &&
            t.CancelledDate == null &&
            c.CancelledDate == null
            group new { c.CreditAmount, t.AccountId, p.FullName, p.Id } by new { t.AccountId, p.FullName, p.SSN } into grp
            let sumC = grp.Select(x => x.CreditAmount).Sum()
            select new
            {
                TotalCredit = sumC,
                AccountId = grp.Key.AccountId,
                FullName = grp.Key.FullName,
                Id = grp.Key.Id
            };
query.Where(p => p.TotalServiceCredit > 20);

SQL查询大约在3秒内运行,但我还没有找到让Linq查询完成的耐心。我想知道是否有一些不同我应该做的事情来完成这个"组,总和,有"查询我试着写?我能做些什么来帮助Linq生成更多的格式化SQL吗?

更新

原来sgmoore有正确的想法。性能问题的关键在于他的回答。

这个

之间的区别
let sumC = grp.Select(x => x.CreditAmount).Sum()

和这个

TotalCredit = grp.Sum(x => x.CreditAmount)

是完成的查询与不完成的查询之间的区别。

请参阅下面的修订后的LINQ查询,该查询与SQL几乎同时完成(SQL为5.3秒,LINQ为5.6秒)。

var query = from p in Person
        join t in Transactions
        on p.AccountId equalas t.AccountId
        join c in Credits
        on t.TransactionId = c.TransactionId
        where p.Status == "Active" &&
        p.Type = "AccountHolder" &&
        t.CancelledDate == null &&
        c.CancelledDate == null
        group new { c.CreditAmount, t.AccountId, p.FullName, p.Id } by new { t.AccountId, p.FullName, p.SSN } into grp
        select new
        {
            TotalCredit = grp.Sum(x => x.CreditAmount),
            AccountId = grp.Key.AccountId,
            FullName = grp.Key.FullName,
            Id = grp.Key.Id
        };
query.Where(p => p.TotalServiceCredit > 20);

感谢您的帮助!

1 个答案:

答案 0 :(得分:2)

我不同意WEI_DBA的评论,但如果您需要这样做,那么您可能会发现将其分解为多个查询更容易,例如

    var query1 = from p in Person
        join t in Transactions on p.AccountId equals t.AccountId
        join c in Credits  on t.TransactionId equals c.TransactionId

        where p.Status == "Active" &&
        p.Type = "AccountHolder" &&
        t.CancelledDate == null &&
        c.CancelledDate == null
        select new { c.CreditAmount, t.AccountID, p.FullName, p.Id};


    var query2 = (from p in query1
        group p by new { p.AccountId, p.FullName, p.Id } into grp

        select new
        {
            TotalCredit = grp.Sum(x => x.CreditAmount),
            AccountId   = grp.Key.AccountId,
            FullName    = grp.Key.FullName,
            Id          = grp.Key.Id
        };


    var query3 = (from p in query2 where p.TotalCredit > 20 select p); 

然后你可以让LINQ将它组合成一个sql命令。

与往常一样,检查并验证实际生成的TSQL是个好主意。