W mojej bazie danych mam kilka dzwonków o tym samym numerze. Chcę je wszystkie zdobyć bez powielania. Stworzyłem klasę porównawczą, aby wykonać tę pracę, ale wykonanie funkcji powoduje duże opóźnienie funkcji bez wyraźnego, od 0,6 s do 3,2 s!
Czy robię to dobrze, czy muszę użyć innej metody?
reg.AddRange(
(from a in this.dataContext.reglements
join b in this.dataContext.Clients on a.Id_client equals b.Id
where a.date_v <= datefin && a.date_v >= datedeb
where a.Id_client == b.Id
orderby a.date_v descending
select new Class_reglement
{
nom = b.Nom,
code = b.code,
Numf = a.Numf,
})
.AsEnumerable()
.Distinct(new Compare())
.ToList());
class Compare : IEqualityComparer<Class_reglement>
{
public bool Equals(Class_reglement x, Class_reglement y)
{
if (x.Numf == y.Numf)
{
return true;
}
else { return false; }
}
public int GetHashCode(Class_reglement codeh)
{
return 0;
}
}
c#
linq
iequalitycomparer
Akrem
źródło
źródło
Odpowiedzi:
Twoja
GetHashCode
implementacja zawsze zwraca tę samą wartość.Distinct
opiera się na dobrej funkcji skrótu, aby działać wydajnie, ponieważ wewnętrznie tworzy tabelę skrótów .Przy implementacji interfejsów klas ważne jest, aby zapoznać się z dokumentacją , aby wiedzieć, który kontrakt masz zaimplementować. 1
W Twoim kodzie rozwiązaniem jest przekazanie
GetHashCode
goClass_reglement.Numf.GetHashCode
i odpowiednie wdrożenie.Poza tym Twoja
Equals
metoda jest pełna niepotrzebnego kodu. Można go przepisać w następujący sposób (ta sama semantyka, ¼ kodu, bardziej czytelny):Wreszcie
ToList
połączenie jest niepotrzebne i czasochłonne:AddRange
akceptuje każdą,IEnumerable
więc konwersja do aList
nie jest wymagana.AsEnumerable
jest tutaj również zbędne, ponieważ przetwarzanie wyniku w iAddRange
tak spowoduje to.1 Pisanie kodu bez wiedzy, co właściwie robi, nazywa się programowaniem kultowym cargo . To zaskakująco powszechna praktyka. To zasadniczo nie działa.
źródło
GetHashCode
. Zwróć jednak uwagę, że dokumentacjaIEqualityComparer<T>
nie określa, co zrobić znull
argumentami - ale przykłady podane w artykule również nie obsługująnull
.Wypróbuj ten kod:
Przykład jego użycia to
źródło
GetHashCode
również musi użyć wyrażenia:return _expr.Invoke(obj).GetHashCode();
Zobacz ten post, aby zobaczyć, jak to zrobić.Tylko kod, z implementacją
GetHashCode
iNULL
walidacją:Przykład: lista Class_reglement różni się od Numf
źródło
Włączenie Twojej klasy porównawczej (a dokładniej klasy
AsEnumerable
wywołania, którego potrzebujesz, aby to zadziałało) oznaczało, że logika sortowania przeszła z bazowania na serwerze bazy danych do bycia na kliencie bazy danych (twojej aplikacji). Oznaczało to, że klient musi teraz pobrać, a następnie przetworzyć większą liczbę rekordów, co zawsze będzie mniej wydajne niż wyszukiwanie w bazie danych, w której można użyć odpowiednich indeksów.Zamiast tego należy spróbować opracować klauzulę Where, która spełnia Twoje wymagania, zobacz Używanie IEqualityComparer z klauzulą LINQ to Entities Except, aby uzyskać więcej informacji.
źródło
Jeśli chcesz mieć ogólne rozwiązanie bez boksu:
stosowanie:
źródło
IEquatable<T>
może być o wiele łatwiejszym sposobem na zrobienie tego z nowoczesnymi frameworkami.Otrzymujesz ładną, prostą
bool Equals(T other)
funkcję i nie ma problemów z rzutowaniem lub tworzeniem oddzielnej klasy.Zauważ, że musisz zaimplementować,
GetHashCode
jeśli używasz tego w słowniku lub z czymś podobnymDistinct
.PS. Nie sądzę, aby jakiekolwiek niestandardowe metody Equals działały ze strukturą encji bezpośrednio po stronie bazy danych (myślę, że wiesz o tym, ponieważ robisz AsEnumerable), ale jest to znacznie prostsza metoda wykonania prostego Equals dla ogólnego przypadku.
Jeśli wydaje się, że coś nie działa (na przykład powielone błędy klucza podczas wykonywania ToDictionary), umieść punkt przerwania w Equals, aby upewnić się, że został trafiony, i upewnij się, że
GetHashCode
zdefiniowałeś (za pomocą słowa kluczowego override).źródło
.Equals()
metodą, którą wydajesz się porównywaćother.Hometown
do siebie samego, zamiastthis.Hometown