Запрос C # LINQ (MYSQL EF) - Отдельные и последние записи - PullRequest
5 голосов
/ 30 августа 2011

У меня есть таблица, давайте назовем ее Запись. Содержит: ID (int) | CustID (int) | Время (datetime) | Данные (varchar)

Мне нужна последняя (самая последняя) запись для каждого клиента:

SQL

select * from record as i group by i.custid having max(id);

LINQ версия 1

dgvLatestDistinctRec.DataSource = from g in ee.Records
                                  group g by g.CustID into grp
                                  select grp.LastOrDefault();

Это выдает ошибку:

Исключение System.NotSupportedException не было обработано кодом пользователя Message = LINQ Объектам не распознается метод 'Faizan_Kazi_Utils.Record LastOrDefault [Record ] (System.Collections.Generic.IEnumerable`1 [Faizan_Kazi_Utils.Record ]) ', и этот метод нельзя перевести в магазин выражение. Источник = System.Data.Entity

LINQ версия 2

var list = (from g in ee.Records
            group g by g.CustID into grp
            select grp).ToList();
Record[] list2 = (from grp in list
                  select grp.LastOrDefault()).ToArray();
dgvLatestDistinctRec.DataSource = list2;

Это работает, но неэффективно, поскольку загружает ВСЕ записи из базы данных в память, а затем извлекает только последний (последний член) каждой группы.

Существует ли какое-либо решение LINQ, которое приближает эффективность и удобочитаемость упомянутого решения SQL?

Ответы [ 5 ]

4 голосов
/ 30 августа 2011

Обновление:

var results = (from rec in Record group rec by rec.CustID into grp 
    select new
    {
        CustID = grp.Key,
        ID = grp.OrderByDescending(r => r.ID).Select(x => x.ID).FirstOrDefault(),
        Data = grp.OrderByDescending(r => r.ID).Select(x => x.Data).FirstOrDefault()
    }
);

Итак, я создал тестовую таблицу и написал запрос Linq -> SQL, который будет делать именно то, что вам нужно. Посмотрите на это и дайте мне знать, что вы думаете. Единственное, что нужно иметь в виду, если этот запрос масштабируется, я полагаю, что он будет выполнять запрос к БД для каждой записи CustID после группировки в select new. Единственный способ убедиться в этом - запустить SQL Tracer, когда вы запустите запрос информации о том, что здесь. http://www.foliotek.com/devblog/tuning-sql-server-for-programmers/

Оригинал:

Не могли бы вы сделать что-то подобное? from g in ee.Records where g.CustID == (from x in ee.Records where (g.CustID == x.CustID) && (g.ID == x.Max(ID)).Select(r => r.CustID))

Это весь псевдокод, но, надеюсь, вы поняли идею.

2 голосов
/ 13 апреля 2012

Я, вероятно, слишком поздно, чтобы помочь с вашей проблемой, но у меня была похожая проблема, и я смог получить желаемые результаты с помощью запроса:

from g in ee.Records
group g by g.CustID into grp
from last in (from custRec in grp where custRec.Id == grp.Max(cr => cr.Id) select custRec)
select last
1 голос
/ 30 августа 2011

Что если вы замените LastOrDefault () на простую Last ()? (Да, вам нужно проверить, что таблица ваших записей не пуста)

Потому что я не вижу способа, как MySQL может вернуть вам группу "Default". Это не то, что можно просто перевести на SQL.

1 голос
/ 30 августа 2011

Я думаю, что grp.LastOrDefault (), функция C #, - это то, о чем SQL не знает. LINQ превращает ваш запрос в SQL-запрос для вашего сервера базы данных. Возможно, вы захотите попробовать создать вместо этого хранимую процедуру или другой способ отфильтровать то, что ищете.

Причина, по которой ваш второй запрос работает, заключается в том, что LINQ to SQL возвращает список, а затем вы делаете запрос LINQ (чтобы отфильтровать то, что вам нужно) в списке C #, который реализует интерфейсы IEnumerable / IQueryable и понимает grp. LastOrDefault ().

0 голосов
/ 30 августа 2011

У меня была другая идея:

// Get a list of all the id's i need by:
// grouping by CustID, and then selecting Max ID from each group.
var distinctLatest = (from x in ee.Records
                          group x by x.CustID into grp 
                          select grp.Max(g => g.id)).ToArray();

// List<Record> result = new List<Record>();

//now we can retrieve individual records using the ID's retrieved above
// foreach (int i in distinctLatest)
// {
//    var res = from g in ee.Records where g.id == i select g;
//    var arr = res.ToArray();
//    result.Add(res.First());
// }

// alternate version of foreach
dgvLatestDistinctRec.DataSource = from g in ee.Records
                                           join i in distinctLatest
                                           on g.id equals i
                                           select g;
...