2011-08-29 12 views
5

Mam stół, nazwijmy go Nagrywanie. Zawierające: ID (int) | CustID (int) | Czas (data/godzina) Danych (varchar)Zapytanie C# LINQ (MYSQL EF) - Odrębne i najnowsze zapisy

muszę ostatnią (najnowszy) rekord dla każdego klienta:

SQL wersji

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(); 

To rzuca błąd:

System.NotSupportedException was unhandled by user code Message=LINQ to Entities does not recognize the method 'Faizan_Kazi_Utils.Record LastOrDefault[Record ](System.Collections.Generic.IEnumerable`1[Faizan_Kazi_Utils.Record ])' method, and this method cannot be translated into a store expression. Source=System.Data.Entity

LINQ wersja 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; 

To działa, ale jest nieefektywne, ponieważ ładuje wszystkie rekordy z bazy danych do pamięci, a następnie wydobywa tylko ostatni (najnowszy członek) z każdej grupy.

Czy istnieje rozwiązanie LINQ, które zbliża się do wydajności i czytelności wspomnianego rozwiązania SQL?

+0

Jak osiągnąć Mysql + LINQ. Czy DBSet obsługuje Mysql. Jeśli tak, czy możesz powiedzieć, w jaki sposób? Musiałem to osiągnąć i poddałem się w zeszłym tygodniu. – prabhakaran

+0

Potrzebuję tylko podstawowych punktów, przynajmniej tam, gdzie wstawiasz ten ciąg połączenia. – prabhakaran

Odpowiedz

4

Aktualizacja:

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() 
    } 
); 

Więc zrobiłem tabelę testową i napisał LINQ -> zapytanie SQL, który zrobi dokładnie to, czego potrzebują. Spójrz na to i daj mi znać, co myślisz. Jedyna rzecz, o której należy pamiętać, jeśli zapytanie jest skalowane. Wierzę, że uruchomi zapytanie do bazy danych dla każdego rekordu CustID po zgrupowaniu w selekcji new. Jedynym sposobem, aby mieć pewność, byłoby uruchomić SQL Tracer po uruchomieniu kwerendy dla informacji na ten temat kliknij tutaj .. http://www.foliotek.com/devblog/tuning-sql-server-for-programmers/

oryginalny:

mógłby zrobić coś takiego? 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))

To wszystko pseudo kod, ale mam nadzieję, że masz pomysł.

+0

Ok, więc próbowałem o czym mówisz i jego dawaniu błędów w dwóch wheres: Delegate System.Func 'nie przyjmuje 1 argumentów –

+0

i na ID w Max (ID) jego podanie: nazwa "id" nie istnieje w bieżącym kontekście –

+0

Dostaję to, co próbujesz zrobić, ale nie udało mi się wprowadzić wymaganych zmian, aby to działało: s –

1

Myślę, że grp.LastOrDefault(), funkcja C#, jest coś, o czym SQL nie wie. LINQ zamienia twoje zapytanie na zapytanie SQL dla twojego serwera db, aby to zrozumieć. Zamiast tego możesz spróbować utworzyć procedurę składowaną lub inny sposób odfiltrowania tego, czego szukasz.

Powód, dla którego działa drugie zapytanie, polega na tym, że LINQ do SQL zwraca listę, a następnie wykonujesz kwerendę LINQ (aby odfiltrować to, czego potrzebujesz) na liście C#, która implementuje interfejsy IEnumerable/IQueryable i rozumie parametry .LastOrDefault().

+0

Prawda, LastOrDefault nie jest zaimplementowana w dostawcy MySQL Entity Framework (jak pokazuje błąd). –

+0

Yup, zwraca długą listę jako zbiór pamięci, który jest następnie filtrowany do pojedynczych wpisów na CustID, co nie jest idealne pod względem wykorzystania pamięci i procesora. I dlatego szukam pomocy tutaj :) –

1

Co w przypadku zastąpienia LastOrDefault() prostym Last()? (Tak, będziesz musiał sprawdzić swoją tabelę rekordów nie jest pusta)

Ponieważ nie widzę sposobu, w jaki MySQL może zwrócić Ci "domyślną" grupę. To nie jest coś, co można po prostu przetłumaczyć na SQL.

+0

Kiedy używam Last I get ten błąd: System.NotSupportedException był nieobsługiwany przez kod użytkownika Message = LINQ do Entities nie rozpoznaje metody "Faizan_Kazi_Utils.Record Last [Record] (System .Collections.Generic.IEnumerable'1 [Faizan_Kazi_Utils.Record]) 'metoda, a tej metody nie można przetłumaczyć na wyrażenie składowe. Źródło = System.Data.Entity –

0

miałam inny pomysł:

// 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; 
+0

jest to trochę oparte na rozwiązaniu bigamilów ... wygenerowało to strumień myśli w mojej głowie –

+0

Naprawdę nie chcesz robić .ToArray() lub ToList() w tym momencie, ponieważ to zwróci wszystkie rekordy i umieści je w pamięć. Chcesz Linq -> SQL, aby wykonać całą pracę. Zasadniczo buduje dynamiczne drzewo wyrażeń i faktycznie nie wykonuje żadnego SQL dopóki nie zażądasz wartości. Najważniejsze rzeczy, które wymagają vall (ToList(), ToArray(), First(), Last() itp.) Przepraszam, jeśli jestem zbyteczna. W każdym razie zaktualizowałem moją odpowiedź, aby zrobić dokładnie to, czego potrzebujesz. Proszę wznowić/zaznaczyć mnie jako odpowiedź, jeśli to działa dla Ciebie! Mam nadzieję, że było to pomocne: – bigamil

+0

hmmm ... ale pierwsza. ToRabka ładuje tylko kilka liczb całkowitych do pamięci (wyraźny identyfikator klienta), a następnie drugi dokładnie robi to, czego potrzebuję (ładowanie całych rekordów: najnowsze zapisy dla każdego odrębnego klienta) ... czy to nie w porządku? –

2

Jestem chyba zbyt późno, aby pomóc z problemem, ale miałem podobny problem i był w stanie uzyskać pożądane wyniki z kwerendy tak:

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 
+0

to było niesamowite. .. dobry występ! –