【问题标题】:How to re-write this inner join subquery from SQL to Lambda如何将此内部连接子查询从 SQL 重写为 Lambda
【发布时间】:2009-12-05 01:32:31
【问题描述】:
SELECT     ulcch.ID, ulcch.UserLoginHistoryID, ulcch.StatusID, 
ulcch.ClientModuleID, ulcch.DeviceState, ulcch.UpdatedAt, ulcch.CreatedAt
FROM         UserLoginClientConnectionHistory AS ulcch INNER JOIN
  (SELECT     MAX(CreatedAt) AS maxCreatedAt
    FROM          UserLoginClientConnectionHistory AS ulcch1
    GROUP BY UserLoginHistoryID) AS m ON m.maxCreatedAt = ulcch.CreatedAt

每天可能有许多“设备状态”更新审核到此登录表中。此查询返回每天最后一个唯一的。

我希望将其重写为 Lambda 语句。这就是我走了多远,我不知道我是否走在正确的轨道上,而我的Max() 正在抛出类型错误,可能是因为 group by 正在制作另一个列表或其他东西...... 希望你能从我的对象示例中解决它....:S

userLogin.UserLoginClientConnectionHistories.Where(x => x.CreatedAt ==
  userLoginClientConnectionHistoryRepository.GetAll(
    GenericStatus.Active).GroupBy(y => y.UserLoginHistoryID).Max(y => y.CreatedAt));

【问题讨论】:

    标签: c# .net sql linq-to-sql lambda


    【解决方案1】:

    我认为这是你想要的:

            var result = userLogin.UserLoginClientConnectionHistories
                .GroupBy(y => new { Id = y.UserLoginHistoryID, Day = y.CreatedAt.Date })
                .Select(x => new
                {
                    Id = x.Key.Id,
                    Day = x.Key.Day,
                    MostRecent = x.Max(y => y.CreatedAt)
                });
    

    这是一个测试平台:

    public class Program
    {
        class LoginEntry
        {
            public int UserLoginHistoryID { get; set; }
            public DateTime CreatedAt { get; set; }
        }
    
        class UserLogin
        {
            public List<LoginEntry> UserLoginClientConnectionHistories = new List<LoginEntry>();
        }
    
        public static void Main(string[] args)
        {
            UserLogin userLogin = new UserLogin();
            userLogin.UserLoginClientConnectionHistories = new List<LoginEntry> {
                new LoginEntry {UserLoginHistoryID = 1, CreatedAt = new DateTime(2009, 1, 1, 3, 0 ,0)},
                new LoginEntry {UserLoginHistoryID = 1, CreatedAt = new DateTime(2009, 1, 1, 15, 0 ,0)},
                new LoginEntry {UserLoginHistoryID = 1, CreatedAt = new DateTime(2009, 1, 3, 11, 0 ,0)},
                new LoginEntry {UserLoginHistoryID = 1, CreatedAt = new DateTime(2009, 1, 1, 10, 0 ,0)},
                new LoginEntry {UserLoginHistoryID = 2, CreatedAt = new DateTime(2009, 1, 3, 4, 0 ,0)},
                new LoginEntry {UserLoginHistoryID = 2, CreatedAt = new DateTime(2009, 1, 3, 5, 0 ,0)},
            };
    
            var result = userLogin.UserLoginClientConnectionHistories
                .GroupBy(y => new { Id = y.UserLoginHistoryID, Day = y.CreatedAt.Date })
                .Select(x => new
                {
                    Id = x.Key.Id,
                    Day = x.Key.Day,
                    MostRecent = x.Max(y => y.CreatedAt)
                });
    
            foreach (var item in result)
            {
                Console.WriteLine("User {0}, day {1}, most recent {2}",
                    item.Id,
                    item.Day,
                    item.MostRecent);
            }
        }
    }
    

    输出:

    User 1, day 01-01-2009 00:00:00, most recent 01-01-2009 15:00:00
    User 1, day 03-01-2009 00:00:00, most recent 03-01-2009 11:00:00
    User 2, day 03-01-2009 00:00:00, most recent 03-01-2009 05:00:00
    

    【讨论】:

      【解决方案2】:

      这里是作为 lambda 的内部连接部分。我假设 CreatedAt 是一个日期时间。

      UserLoginClientConnectionHistory .GroupBy (ulcch1 => 新
      { 名称 = ulcch1.Name }) .选择(g => 新
      { maxCreatedAt = (DateTime?)(g.Max (p => p.CreatedAt)) })

      【讨论】:

        【解决方案3】:

        我想你想按CreatedAt 而不是UserLoginHistoryID 分组:

        var q = userLogin.UserLoginClientConnectionHistories
                    .GroupBy(h => h.CreatedAt)
                    .OrderByDescending(g => g.Key) // Sort by CreatedAt
                    .First()
                    .Select(h => new { h.Id, h.UserLoginHistoryID, ... });
        

        这将返回共享最新CreatedAt 值的UserLoginClientConnectionHistory 条目集。

        【讨论】:

          【解决方案4】:

          感谢你们所有的帮助,我给你们投了赞成票,但你不会相信,但几个小时后,我搜索了一个将 SQL 转换为 LINQ 的程序,令我惊讶的是找到了一个名为“@ 987654321@"。听起来很疯狂,没想到会走得太远,但它运行良好.. 如果其他人陷入同一条船上,绝对值得一试该应用程序...

          检查它返回的庞大查询!分析了一下,不觉得有多余的臃肿吗?任何人有任何优化技巧或发现任何不必要的代码?

                  moduleDeviceStates = from ulh in user.UserLoginHistories
                                       join ulcch in userLogin.UserLoginClientConnectionHistories on new { ID = ulh.ID } equals new { ID = ulcch.UserLoginHistoryID }
                                       join cm in clientModuleRepository.GetAll(GenericStatus.Active) on new { ClientModuleID = ulcch.ClientModuleID } equals new { ClientModuleID = cm.ID }
                                       join mo in moduleRepository.GetAll(GenericStatus.Active) on new { ModuleID = cm.ModuleID } equals new { ModuleID = mo.ID }
                                       join m in
                                           (
                                               (from ulcch1 in userLogin.UserLoginClientConnectionHistories
                                                group ulcch1 by new
                                                {
                                                    ulcch1.UserLoginHistoryID
                                                } into g
                                                select new
                                                {
                                                    maxCreatedAt = g.Max(p => p.CreatedAt)
                                                })) on new { maxCreatedAt = ulcch.CreatedAt } equals new { maxCreatedAt = m.maxCreatedAt }
                                       select new ModuleDeviceState()
                                       {
                                           ModuleID = mo.ID,
                                           Name = mo.Name,
                                           DeviceState = (State.DeviceState)ulcch.DeviceState,
                                           CreatedAt = ulcch.CreatedAt
                                       };
          

          为您的帮助干杯 dahlbyk,但我确实想对 UserLoginHistoryID 进行分组,在深入研究 lambda 等效项之前,我已在 SQL 中确认了我的查询 :) 谢谢。


          @Mark感谢您花时间回复,是的,我每天为每个用户执行[last]条目(userloginhistory ..它又包含一个userID),并将我的sql导出到linq查询确实产生了我想要的(可以在下面的查询结果中看到;这就是我想要的。您每天看到双重条目的原因是因为还附加了 ClientModule 的..所以我真的想要所有客户端模块,每天每个登录条目 - 太难了在讨论论坛上获得编程要求啊!)也许你的做完全相同的事情(如果我正确阅读你的输出,它似乎)只是更加精简。

          看到我不太了解你在那里使用GroupBySelect 进行的匿名转换,但现在我明白了,这是有道理的。我可能会给你一个机会。希望我也可以对其进行调整,以包括每天不同的 ClientModule。所以无论如何..这是我的 SQL 的查询结果,实际上是我通过自己的 lambda 得到的结果:

          ID  UserLoginHistoryID  StatusID    ClientModuleID  DeviceState UpdatedAt   CreatedAt
          277 62  1   1   4   NULL    2009-10-31 13:28:59.003
          278 62  1   16  4   NULL    2009-10-31 13:28:59.003
          331 65  1   1   4   NULL    2009-10-31 17:13:28.333
          332 65  1   16  4   NULL    2009-10-31 17:13:28.333
          


          更新标记:您好,在对您的查询进行几次调整之后,我可以在 .NET 中在两个 lambda 语句之间生成相同的对象图。这是我现在要使用的,源自您的,因为它比自动生成的更精简且更易于理解,我将奖励您积分:)

          我在 Group By 中添加了更多条目,因为我的 new ModuleDeviceState 课程需要这些条目。

          moduleDeviceStates = userLogin.UserLoginClientConnectionHistories
                              .GroupBy(y => new { Id = y.UserLoginHistoryID, 
                                  CreatedAt = y.CreatedAt.Date, 
                                  ModuleID = y.ClientModule.ModuleID, 
                                  ModuleName = y.ClientModule.Module.Name,
                                  DeviceState = y.DeviceState })
                              .Select(x => new ModuleDeviceState()
                                               {
                                                   ModuleID = x.Key.ModuleID, 
                                                   Name = x.Key.ModuleName,
                                                   DeviceState = (State.DeviceState)x.Key.DeviceState,
                                                   CreatedAt = x.Max(y => y.CreatedAt)
                                               });
          

          【讨论】:

          • 在您的问题中,您说您想要“每天最后一个唯一的 [每个用户的条目]”。但如果我没看错的话,这个查询不会返回每天的记录——只有每个用户的总体最大值。我错过了什么?我已经发布了一个我认为可以满足您的问题要求的答案。
          猜你喜欢
          • 1970-01-01
          • 2016-06-14
          • 1970-01-01
          • 2012-05-22
          • 2020-07-15
          • 1970-01-01
          • 2021-06-23
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多