Ich habe einige Glocken in meiner Datenbank mit der gleichen Nummer. Ich möchte alle ohne Verdoppelung bekommen. Dann erstelle ich eine Vergleichsklasse, um diese Arbeit zu erledigen, aber die Ausführung der Funktion führt zu einer großen Verzögerung der Funktion ohne eindeutige Verzögerung von 0,6 bis 3,2 Sekunden!
Mache ich es richtig oder muss ich eine andere Methode verwenden?
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;
}
}
Kein Wunder, wenn man Ihre GetHashCode
-Implementierung betrachtet, die immer denselben Wert zurückgibt. Distinct
ist auf eine gute Hash-Funktion angewiesen, um effizient arbeiten zu können.
Bei der Implementierung von Schnittstellen für Klassen müssen Sie deren Dokumentation first lesen, andernfalls wissen Sie nicht, welchen Vertrag Sie ausführen sollen.1
In Ihrem Code besteht die Lösung darin, GetHashCode
an Class_reglement.Numf.GetHashCode
weiterzuleiten und dort entsprechend zu implementieren.
Abgesehen davon ist Ihre Equals
-Methode mit unnötigem Code gefüllt. Es könnte wie folgt umgeschrieben werden (gleiche Semantik, ¼ des Codes, lesbarer):
public bool Equals(Class_reglement x, Class_reglement y)
{
return x.Numf == y.Numf;
}
Darüber hinaus ist der Aufruf ToList
nicht erforderlich und zeitaufwändig: AddRange
akzeptiert alle IEnumerable
-Werte, sodass keine Konvertierung in eine List
-Anweisung erforderlich ist. AsEnumerable
ist auch hier redundant, da die Verarbeitung des Ergebnisses in AddRange
dies ohnehin bewirkt.
1 Die Implementierung von Code, ohne zu wissen, was er tatsächlich tut, heißt cargo cult programming . Es ist eine überraschend weit verbreitete Praxis. Es funktioniert grundsätzlich nicht.
Versuchen Sie diesen Code:
public class GenericCompare<T> : IEqualityComparer<T> where T : class
{
private Func<T, object> _expr { get; set; }
public GenericCompare(Func<T, object> expr)
{
this._expr = expr;
}
public bool Equals(T x, T y)
{
var first = _expr.Invoke(x);
var sec = _expr.Invoke(y);
if (first != null && first.Equals(sec))
return true;
else
return false;
}
public int GetHashCode(T obj)
{
return obj.GetHashCode();
}
}
Ein Beispiel für seine Verwendung wäre
collection = collection
.Except(ExistedDataEles, new GenericCompare<DataEle>(x=>x.Id))
.ToList();
Die Einbeziehung Ihrer Vergleichsklasse (oder genauer der AsEnumerable
-Aufruf, die Sie verwenden mussten, um sie zum Laufen zu bringen) bedeutete, dass die Sortierlogik nicht mehr vom Datenbankserver, sondern vom Datenbankclient (Ihrer Anwendung) abhing. Dies bedeutet, dass Ihr Client jetzt eine größere Anzahl von Datensätzen abrufen und verarbeiten muss. Dies ist immer weniger effizient als das Durchsuchen der Datenbank, in der die entsprechenden Indizes verwendet werden können.
Sie sollten versuchen, eine Where-Klausel zu entwickeln, die Ihren Anforderungen entspricht. Weitere Informationen finden Sie unter Verwenden eines IEqualityComparer mit einer LINQ to Entities Except-Klausel .
Wenn Sie eine generische Lösung ohne Boxen wünschen:
public class KeyBasedEqualityComparer<T, TKey> : IEqualityComparer<T>
{
private readonly Func<T, TKey> _keyGetter;
public KeyBasedEqualityComparer(Func<T, TKey> keyGetter)
{
_keyGetter = keyGetter;
}
public bool Equals(T x, T y)
{
return EqualityComparer<TKey>.Default.Equals(_keyGetter(x), _keyGetter(y));
}
public int GetHashCode(T obj)
{
TKey key = _keyGetter(obj);
return key == null ? 0 : key.GetHashCode();
}
}
public static class KeyBasedEqualityComparer<T>
{
public static KeyBasedEqualityComparer<T, TKey> Create<TKey>(Func<T, TKey> keyGetter)
{
return new KeyBasedEqualityComparer<T, TKey>(keyGetter);
}
}
verwendungszweck:
KeyBasedEqualityComparer<Class_reglement>.Create(x => x.Numf)
Einfach Code mit Implementierung der Validierung GetHashCode
und NULL
:
public class Class_reglementComparer : IEqualityComparer<Class_reglement>
{
public bool Equals(Class_reglement x, Class_reglement y)
{
if (x is null || y is null))
return false;
return x.Numf == y.Numf;
}
public int GetHashCode(Class_reglement product)
{
//Check whether the object is null
if (product is null) return 0;
//Get hash code for the Numf field if it is not null.
int hashNumf = product.hashNumf == null ? 0 : product.hashNumf.GetHashCode();
return hashNumf;
}
}
Beispiel: Liste von Class_reglement unterscheidbar nach Numf
List<Class_reglement> items = items.Distinct(new Class_reglementComparer());