sql - .Net Core Entity Framework Linq Fluent API 查询不会创建/执行在数据库上运行的正确 SQL 查询

标签 sql entity-framework linq entity-framework-core

我写了这个 SQL 查询:

SELECT R.Name, R.PointsNeeded, A.EmailAddress, SUM(PH.Points) AS TotalPoints
FROM Business AS B
INNER JOIN Reward AS R ON R.BusinessId = B.Id
INNER JOIN Account AS A ON A.BusinessId = B.Id
INNER JOIN PointHistory PH ON PH.AccountId = A.Id
WHERE B.Serial = 'F5C17337-F675-4270-8A57-FE2F5782B5CB'
GROUP BY R.Name, A.EmailAddress, R.PointsNeeded
HAVING SUM(PH.Points) >= R.PointsNeeded
ORDER BY A.EmailAddress ASC

返回 3 个结果。我想使用 linq/fluent api 创建它。我不知道如何做 HAVING 所以我创建了这个:

var eligableAccounts = _context.Business
           .Join(_context.Reward, B => B.Id, R => R.BusinessId, (Business, Rewards) => new { Business, Rewards })
           .Join(_context.Account, BusinessRewards => BusinessRewards.Business.Id, A => A.BusinessId, (BusinessRewards, Account) => new
           {
               Business = BusinessRewards.Business,
               Rewards = BusinessRewards.Rewards,
               Account = Account
           })
            .Join(_context.PointHistory, Model => Model.Account.Id, PointHistory => PointHistory.AccountId, (Model, PointHistory) => new
            {
                Business = Model.Business,
                Rewards = Model.Rewards,
                Account = Model.Account,
                PointHistory = PointHistory
            })
            .Where(Model => Model.Business.Serial == businessSerial)
            .GroupBy(Model => new { Model.Rewards.Name, Model.Account.EmailAddress, Model.Rewards.PointsNeeded })
            .Where(Group => Group.Sum(Model => Model.PointHistory.Points) >= Group.Key.PointsNeeded)
            .Select(Group => new {
                TotalPoints = Group.Sum(Model => Model.PointHistory.Points),
                EmailAddress = Group.Key.EmailAddress,
                RewardName = Group.Key.Name,
                PointsNeeded = Group.Key.PointsNeeded
            }).ToList();

这有效,eligableAccounts 包含与我的 SQL 查询在 SQL Management Studio 中直接执行时返回的相同的 3 个结果。我想看看幕后运行的是什么,令我惊讶的是,每个结果集都被返回,然后 .net 正在做一些神奇的调味料以仅获得我需要的 3 条记录。这是 EF 在数据库上实际执行的内容:

exec sp_executesql N'SELECT [B].[Id], [B].[Code], [B].[LastProcessedDateTime], [B].[Name], [B].[PointRatio], [B].[Serial], [Rewards].[Id], [Rewards].[BusinessId], [Rewards].[Name], [Rewards].[PointsNeeded], [Account].[Id], [Account].[BusinessId], [Account].[City], [Account].[Created], [Account].[EmailAddress], [Account].[EmailSent], [Account].[FirstName], [Account].[LastName], [Account].[Password], [Account].[PasswordSalt], [Account].[Phone], [Account].[RoleId], [Account].[State], [Account].[Updated], [Account].[VerificationCode], [Account].[Verified], [Account].[ZipCode], [PointHistory].[Id], [PointHistory].[AccountId], [PointHistory].[Points], [PointHistory].[TransactionDate], [PointHistory].[TransactionType]
FROM [Business] AS [B]
INNER JOIN [Reward] AS [Rewards] ON [B].[Id] = [Rewards].[BusinessId]
INNER JOIN [Account] AS [Account] ON [B].[Id] = [Account].[BusinessId]
INNER JOIN [PointHistory] AS [PointHistory] ON [Account].[Id] = [PointHistory].[AccountId]
WHERE [B].[Serial] = @__businessSerial_0
ORDER BY [Rewards].[Name], [Account].[EmailAddress], [Rewards].[PointsNeeded]',N'@__businessSerial_0 nvarchar(4000)',@__businessSerial_0=N'F5C17337-F675-4270-8A57-FE2F5782B5CB'

此 SQL 直接在数据库上执行时会返回所有结果,因为 HAVING 语句不是由 EF 创建的。有谁知道我如何编写我的 EF 代码来生成执行的正确查询?这可能会开始返回数十万条记录,我不喜欢 .net 处理内存中结果集缩减的想法。我宁愿把它推到数据库中。如果我必须创建一个存储过程,我可以这样做,但我真的不想这样做。任何帮助表示赞赏。谢谢!

最佳答案

虽然我无法修复 EF Core 的限制(除非您想切换到完整的 EF),但可以将您的 SQL 转换为 LINQ。我发现像这样使用查询语法进行分组更容易:

var ans = from b in _context.Business
          join r in _context.Reward on b.Id equals r.BusinessId
          join a in _context.Account on b.Id equals a.BusinessId
          join ph in _context.PointHistory on a.Id equals ph.AccountId
          where b.Serial == "F5C17337-F675-4270-8A57-FE2F5782B5CB"
          group new { b, r, a, ph } by new { r.Name, a.EmailAddress, r.PointsNeeded } into grp
          let TotalPoints = grp.Sum(g => g.ph.Points)
          where TotalPoints >= grp.Key.PointsNeeded
          orderby grp.Key.EmailAddress
          select new { grp.Key.Name, grp.Key.PointsNeeded, grp.Key.EmailAddress, TotalPoints };

请注意翻译是直截了当的,几乎是机械的。

在我看来,您使用 lambda 语法的翻译看起来很直接。

关于sql - .Net Core Entity Framework Linq Fluent API 查询不会创建/执行在数据库上运行的正确 SQL 查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46494024/

相关文章:

c# - 过滤复杂对象数组的优雅方式

c# - lambda 表达式中的语句和返回 lambda

c# - 检查 Collection 中的所有项目是否具有相同的值

mysql - 我应该在这个例子中使用外键吗?

c# - 如何在我的强类型 ASP.NET MVC 创建和编辑 View 的 DropDownList 中使用实体对象导航属性?

sql - 事件目录 : Convert canonicalName node value from string to integer

entity-framework - Entity Framework 4.1+ 多对多关系变更跟踪

c# - 有人可以向我解释一下这个 LINQ/Entity Framework 查询实际上是如何工作的吗?

sql - Grails - 通过对域中的多个元素进行分组和汇总来检索数据

mysql - SELECT 与另一个 SELECT 的 COUNT