如何将此内连接子查询从SQL重写为Lambda

时间:2009-12-05 01:32:32

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

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()正在抛出一个类型错误,可能是因为该组正在制作另一个列表或其他内容...... 希望你能从我的对象例子中解决它....:S

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

4 个答案:

答案 0 :(得分:1)

这是作为lambda的内部连接部分。我假设CreatedAt是一个dateTime。

UserLoginClientConnectionHistory    .GroupBy(ulcc​​h1 =>          新
         {             Name = ulcch1.Name          })    。选择(g =>          新
         {             maxCreatedAt =(DateTime?)(g.Max(p => p.CreatedAt))          })

答案 1 :(得分:1)

我认为您希望按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, ... });

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

答案 2 :(得分: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

答案 3 :(得分:0)

感谢所有帮助人员,我已经投了你们所有人,但你们不会相信,但几个小时后我搜索了一个程序将SQL转换为LINQ,令我惊讶的是发现了一个名为“{ {3}}”。听起来很疯狂,并没有想到会走得太远,但它运作得很完美......如果有其他人被卡在同一条船上,绝对值得一试这个应用......

检查它返回的庞大查询!在分析之后,不要认为它有额外膨胀吗?任何人都有任何优化提示或发现任何不必要的代码?

        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感谢您抽出时间回复,是的,我每天都按照每个用户[userloginhistory ...进而包含一个用户ID)的[last]条目,并将我的sql导出到linq查询确实产生了我想要的东西(这可以在下面的查询结果中看到;这就是我想要的。你每天看到双重条目的原因是因为还附加了ClientModule的..所以我真的想要所有客户端模块,每天每次登录条目 - 这么难在讨论论坛上获得编程要求argh!)也许你的做法完全相同(看起来如果我正确地阅读你的输出)只是更精简。

看到我不太了解你用GroupBySelect完成的那个anon投射,但现在我看到它,这是有意义的。我可能会给你一个机会。希望我能给它一个调整,包括每天不同的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

<小时/> 更新标记:您好了,经过对查询的几次调整后,我可以在两个lambda语句之间生成相同的.NET对象图。这是我现在将使用的,因为它比自动生成的更简化,更容易理解,我将奖励你积分:)

我向小组添加了一些条目,因为我需要为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)
                                     });