Как переписать этот внутренний подзапрос соединения из SQL в Lambda - PullRequest
0 голосов
/ 05 декабря 2009
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

В эту таблицу входа в систему может быть много обновлений состояния устройства в день. Этот запрос возвращает последний уникальный для каждого дня.

Я бы хотел переписать это как лямбда-выражение. Это то, как далеко я продвинулся, я не знаю, нахожусь ли я на правильном пути, и мой Max() выдает ошибку типа, возможно, потому что группа делает другой список или что-то ... Надеюсь, что вы можете решить это из моих примеров объектов ....: S

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

Ответы [ 4 ]

1 голос
/ 05 декабря 2009

Я думаю, что это то, что вы хотите:

        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
1 голос
/ 05 декабря 2009

Я думаю, вы хотите сгруппировать по 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.

1 голос
/ 05 декабря 2009

Вот часть внутреннего соединения в виде лямбды. Я предположил, что CreatedAt было dateTime.

UserLoginClientConnectionHistory .GroupBy (ulcch1 => новый
{ Имя = ulcch1.Name }) . Выбрать (g => новый
{ maxCreatedAt = (DateTime?) (g.Max (p => p.CreatedAt)) })

0 голосов
/ 05 декабря 2009

Спасибо за вашу помощь, ребята, я вас всех проголосовал, но вы не поверите, но несколько часов спустя я искал программу для преобразования SQL в LINQ, и, к моему удивлению, нашел программу под названием " Linqer ». Звучит безумно и не ожидал, что уйду далеко, но это сработало отлично ... определенно стоит проверить это приложение, если кто-то застрянет в той же лодке ...

Проверьте гигантский запрос, который он возвратил! Проанализировав это, не думайте, что это лишнее раздувание? У кого-нибудь есть какие-либо советы по оптимизации или обнаружен какой-либо ненужный код?

        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, мой запрос был подтвержден в SQL, прежде чем углубляться в лямбда-эквивалент :) спасибо.


@Mark Спасибо, что нашли время ответить, да, я делаю то, что [последние] записи для пользователя (userloginhistory .. который, в свою очередь, содержит идентификатор пользователя) для каждого дня, и экспорт моего sql в запрос linq действительно дал то, что я хотел ( что можно увидеть в результате запроса ниже, это то, что я хочу. Причина, по которой вы видите двойные записи для каждого дня, заключается в том, что к нему также прикреплены модули ClientModule .. поэтому я действительно хочу, чтобы все клиентские модули на каждую запись для входа в день - так сложно чтобы получить требования к программированию через дискуссионный форум, аааа!) Возможно, ваш делает то же самое (кажется, если я правильно читаю ваш вывод) просто намного более упорядоченным.

Понимаете, я не слишком много знал о том, как вы кастовали анон с GroupBy и Select, но теперь я вижу это, это имеет смысл. Я могу попробовать. Надеюсь, я смогу также настроить различные модули ClientModule на день. Так или иначе .. вот результат запроса от моего SQL, и фактически то, что я получил через свою собственную лямбду:

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 между обоими лямбда-операторами. Это то, что я буду использовать сейчас, полученное от вашего, так как оно более упорядочено и легче для понимания, чем у auto-gen'd, и я начислю вам очки:)

Я добавил еще несколько записей в Группу, поскольку мне это нужно для моего 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)
                                     });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...