データベースには同じ番号の鐘がいくつかあります。重複することなくそれらすべてを取得したいです。次に、この作業を行うために比較クラスを作成しますが、関数の実行は、0.6秒から3.2秒まで、明確に関数から大きな遅延を生じます!
私はそれを正しくやっていますか、別の方法を使用する必要がありますか?
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;
}
}
常に同じ値を返すGetHashCode
実装を検討するのも当然です。 Distinct
は、効率的に機能するために適切なハッシュ関数に依存しています。
クラスのインターフェースを実装する場合、 documentation firstを読む必要があります。実装する。1
コード内での解決策は、GetHashCode
をClass_reglement.Numf.GetHashCode
に転送し、そこで適切に実装することです。
それとは別に、Equals
メソッドには不要なコードがいっぱいです。次のように書き換えることができます(同じセマンティクス、コードの1/4、より読みやすい):
public bool Equals(Class_reglement x, Class_reglement y)
{
return x.Numf == y.Numf;
}
さらに、ToList
呼び出しは不要で時間がかかります。AddRange
はIEnumerable
を受け入れるため、List
への変換は必要ありません。 AsEnumerable
は結果をAddRange
で処理するととにかくこれが発生するため、ここではalsoも冗長です。
1 実際に何をするのか知らずにコードを実装することを cargo cult programming と呼びます。それは驚くほど広く行われている習慣です。基本的に機能しません。
このコードを試してください:
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();
}
}
その使用例は
collection = collection
.Except(ExistedDataEles, new GenericCompare<DataEle>(x=>x.Id))
.ToList();
GetHashCode
および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;
}
}
例:Class_reglementのリストNumf
List<Class_reglement> items = items.Distinct(new Class_reglementComparer());
比較クラス(または、より具体的には、それを機能させるために使用する必要があるAsEnumerable
呼び出し)を含めることは、ソートロジックがデータベースサーバーに基づくものからデータベースクライアント(アプリケーション)にあることを意味します。これは、クライアントが大量のレコードを取得して処理する必要があることを意味し、適切なインデックスを使用できるデータベースでルックアップを実行するよりも常に効率が低下します。
代わりに、要件を満たすwhere句の開発を試みる必要があります。詳細については、 LINQ to Entities Except句でのIEqualityComparerの使用 を参照してください。
ボクシングなしの一般的なソリューションが必要な場合:
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);
}
}
使用法:
KeyBasedEqualityComparer<Class_reglement>.Create(x => x.Numf)