Получите различные записи на основе столбца Specifi c в Entity Framework - PullRequest
0 голосов
/ 28 марта 2020

У меня есть таблица SQLite, которая содержит каждый результат теста, который мы запустили, и я пытаюсь написать запрос структуры сущностей, который возвращает только самый последний результат теста для проекта.

Обычно, я бы предположил, что это будет «группировка по идентификатору проекта, возвращаемая строка с максимальным обновленным значением» или, альтернативно, «сортировка по дате и возврат в первую очередь». Однако, когда я пытаюсь выполнить запрос, я получаю ошибки Entity Framework, которые «не могут быть переведены».

Вот что я пробовал:

results = await _context.Results
            .Include(x => x.Project)
            .AsNoTracking()
            .OrderByDescending(x => x.Updated)
            .GroupBy(x => x.ProjectId, (x, y) => y.First())
            .ToListAsync();

Однако я продолжаю получать сообщения о том, что команда .First() не может быть переведена Entity Framework. Есть ли что-то, что я упускаю (или, альтернативно, лучший способ написания запроса, который более дружествен к фреймворку сущностей)?

Для справки, вот операция, которую я пытаюсь выполнить в обычном режиме SQL : https://thoughtbot.com/blog/ordering-within-a-sql-group-by-clause

Я бы предпочел сделать как можно больше работы на сервере, потому что проектов мало, но результатов может быть тысячи и я бы предпочел не делать фильтрацию на стороне клиента, если это возможно.

Приложение написано для ASP. NET Core 3.1, с использованием Entity Framework Core.

Незначительное редактирование: пока SQLite используется для разработки, окончательный код будет работать с SQL Сервером, отсюда и желание выполнять обработку на стороне сервера.

Ответы [ 3 ]

1 голос
/ 28 марта 2020

Попробуйте использовать подзапрос вместо группировки. Как это:

results = await _context.Results
            .Include(x => x.Project)
            .AsNoTracking() 
            .Where( r => r.Id == _context.Results.Where( rr => rr.ProjectId == r.ProjectID).Max( rr => rr.Id) )
            .ToListAsync();
0 голосов
/ 28 марта 2020

Хотя это не переносимо, вот как это можно сделать, используя SQLite-совместимые SQL и Entity Framework:

results = await _context.Results
    .FromSqlRaw("SELECT Results.* FROM (SELECT Id, ProjectId, MAX(Updated) as Updated " +
    "FROM Results GROUP BY ProjectId) as latest_results " +
    "INNER JOIN Results ON Results.Id = latest_results.Id")
    .Include(x => x.Project) //not required for question but useful
    .OrderBy(x => x.Project.Name)
    .AsNoTracking()
    .ToListAsync();

Если у кого-то есть способ сделать это в чистом LINQ / EF, но все же выполняя запрос на стороне сервера, я с радостью отмечу это как ответ, поскольку это зависит от используемого диалекта SQL.

0 голосов
/ 28 марта 2020

Ваш метод не может быть переведен в T- SQL, Linq to Entities не может его распознать. Вы можете изменить код, как показано ниже (добавив AsEnumerable после AsNoTracking):

.Include(x => x.Project)
.AsNoTracking()
.AsEnumerable()

С AsEnumerable после загрузки данных, любая дальнейшая операция выполняется с использованием Linq для Объекты, по данным уже в памяти.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...