Jak zaimplementować Ieequalitycomparer, aby zwrócić różne wartości?

Mam zapytanie L2E, które zwraca dane zawierające zduplikowane obiekty. Muszę usunąć te duplikaty obiektów. Zasadniczo powinienem założyć, że jeśli ich identyfikatory są takie same, to obiekty są zduplikowane. Próbowałem q.Distinct(), ale to wciąż zwracało zduplikowane obiekty. Następnie próbowałem zaimplementować własny Ieequalitycomparer i przekazać go do metody Distinct(). Metoda nie powiodła się z następującym tekstem:

LINQ to Entities nie rozpoznaje metody "System.Linq.IQueryable 1[DAL.MyDOClass] Distinct[MyDOClass](System.Linq.IQueryable 1 [DAL.MyDOClass], System.Kolekcje.Ogólne.Ieequalitycomparer " 1[DAL.MyDOClass])" method, a tej metody nie można przetłumaczyć na wyrażenie store.

A oto implementacja EqualityComparer:

  internal class MyDOClassComparer: EqualityComparer<MyDOClass>
    {
        public override bool Equals(MyDOClass x, MyDOClass y)
        {
            return x.Id == y.Id;
        }

        public override int GetHashCode(MyDOClass obj)
        {
            return obj == null ? 0 : obj.Id;
        }
    }

Jak więc poprawnie napisać własne IEqualityComparer?

Author: Eranga, 2011-12-19

4 answers

An EqualityComparer nie jest drogą do zrobienia - może tylko filtrować wynik ustawiony w pamięci np:

var objects = yourResults.ToEnumerable().Distinct(yourEqualityComparer);

Możesz użyć metody GroupBy do grupowania według identyfikatorów i metody First, aby Twoja baza danych mogła pobierać tylko unikalny wpis na ID np:

var objects = yourResults.GroupBy(o => o.Id).Select(g => g.First());
 138
Author: Rich O'Kelly,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-20 08:07:27

Rich.okelly i Ladislav Mrnka są poprawni na różne sposoby.

Obie odpowiedzi dotyczą faktu, że metody IEqualityComparer<T> nie zostaną przetłumaczone na SQL.

Myślę, że warto przyjrzeć się za i przeciw każdemu, co zajmie trochę więcej niż komentarz.

Podejście Rich ' a ponownie zapisuje zapytanie do innego zapytania z tym samym ostatecznym rezultatem. Ich kod powinien skutkować mniej więcej tym, jak sprawnie byś to zrobił z kodowaniem ręcznym SQL.

Ladislav wyciąga go z bazy danych w punkcie przed odrębnym, a następnie podejście w pamięci zadziała.

Ponieważ baza danych świetnie radzi sobie z grupowaniem i filtrowaniem, od których zależy rich, będzie prawdopodobnie najbardziej wydajna w tym przypadku. Można jednak zauważyć, że złożoność tego, co dzieje się przed tym grupowaniem, jest taka, że Linq-to-entities nie generuje ładnie pojedynczego zapytania, ale raczej produkuje kilka zapytań, a następnie robi kilka pracy w pamięci, co może być dość paskudne.

Ogólnie grupowanie jest droższe niż rozróżnianie w przypadkach w pamięci (zwłaszcza jeśli wprowadzasz je do pamięci za pomocą AsList() zamiast AsEnumerable()). Tak więc, jeśli albo zamierzałeś już przynieść go do pamięci na tym etapie z powodu jakiegoś innego wymogu, byłoby to bardziej wydajne.

Byłoby również jedynym wyborem, gdyby twoja definicja równości była czymś, co nie odnosiło się dobrze do tego, co jest dostępne tylko w bazie danych, a oczywiście pozwala na zmianę definicji równości, jeśli chcesz to zrobić na podstawie IEqualityComparer<T> przekazanej jako parametr.

W sumie, rich 's jest odpowiedzią, którą powiedziałbym, że będzie najbardziej-prawdopodobnie będzie najlepszym wyborem tutaj, ale różne plusy i minusy Ladislava w porównaniu do rich' s sprawiają, że jest to również warte studiowania i rozważenia.

 18
Author: Jon Hanna,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-19 13:29:58

Nie zrobisz tego. Distinct operator jest wywoływany w bazie danych, więc każdy kod, który piszesz w aplikacji ,nie może być użyty (nie możesz przenieść logiki porównywania równości do SQL), chyba że jesteś zadowolony z załadowania wszystkich niezrównanych wartości i utworzenia odrębnego filtrowania w aplikacji.

var query = (from x in context.EntitySet where ...).ToList()
                                                   .Distinct(yourComparer);
 8
Author: Ladislav Mrnka,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-19 11:54:11

Późna odpowiedź, ale można zrobić lepiej: jeśli obiekt DAL jest częściowy (zwykle jest, jeśli jest obiektem DB), można go rozszerzyć w następujący sposób:

public partial class MyDOClass :  IEquatable<MyDOClass>
    {

        public override int GetHashCode()
        {
            return Id == 0 ? 0 : Id;
        }

        public bool Equals(MyDOClass other)
        {
            return this.Id == other.Id;
        }
    }

I distinct będzie działać bez żadnych przeciążeń w nim.

Jeśli nie, możesz utworzyć klasę Ieequalitycomparer w następujący sposób:

internal class MyDOClassComparer : MyDOClass,  IEquatable<MyDOClass>, IEqualityComparer<MyDOClass>
    {
        public override int GetHashCode()
        {
            return Id == 0 ? 0 : Id;
        }

        public bool Equals(MyDOClass other)
        {
            return this.Id == other.Id;
        }

        public bool Equals(MyDOClass x, MyDOClass y)
        {
            return x.Id == y.Id;
        }

        public int GetHashCode(MyDOClass obj)
        {
            return Id == 0 ? 0 : Id;
        }
    }

I jeszcze raz, użyj distinctive bez żadnego przeciążenia

 4
Author: gil kr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-15 09:44:53