2011-12-19 8 views
32

重複するオブジェクトを含むデータを返すL2Eクエリがあります。それらの重複したオブジェクトを削除する必要があります。基本的には、IDが同じならオブジェクトが重複していると仮定します。私はq.Distinct()を試しましたが、それでも重複したオブジェクトが返されました。それから私は自分のIEqualityComparerを実装し、それをDistinct()メソッドに渡そうとしました。エンティティへ異なる値を返すためにIEqualityComparerを実装するにはどうすればよいですか?

LINQは方法 「System.Linq.IQueryable 1[DAL.MyDOClass] Distinct[MyDOClass](System.Linq.IQueryable 1 [DAL.MyDOClass]を認識しない、 System.Collections.Generic.IEqualityComparer`1 [DAL.MyDOClass:この方法は、以下のテキストで失敗しました]) ' メソッドであり、このメソッドをストア式に変換することはできません。

そしてここ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; 
     } 
    } 

それでは、どのように私はきちんと自分のIEqualityComparerを書くのですか?

答えて

86

EqualityComparerが進むべき道ではない - それだけでメモリなどに設定されたあなたの結果をフィルタリングすることができます

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

あなただけのデータベースをできるようにIDとFirst方法によりグループにGroupByメソッドを使用することができますIDごとにユニークなエントリを取得する例:

var objects = yourResults.GroupBy(o => o.Id).Select(g => g.First()); 
+8

+1ずに個別に使用します。 First()ではなく、.FirstOrDefault()を使用する必要があります –

+0

私はあなたに教育を借りています!それらの答えの1つは、私がアップアップ投票をすることができればと思います! – seebiscuit

+0

@yoelhalbはGroupByの保証をしていません返されたグループは空ではありませんか?グループ化は要素を切り離すことによって形成されるので、返されたグループの1つが空になる方法はありません – vijrox

7

あなたはしません。 Distinct演算子がデータベース上で呼び出されるため、アプリケーションに書かれたコードは使用できません(等価コンパレータロジックをSQLに移動することはできません)。

var query = (from x in context.EntitySet where ...).ToList() 
                .Distinct(yourComparer); 
+4

なぜ' ToEnumerable() 'ではなく' ToList() 'ですか? –

+2

@ジョン:そうです。 'ToEnumerable'で十分でしょう。 –

14

rich.okellyとLadislav Mrnkaは、どちらも異なる方法で正しいです。

両方の答えは、IEqualityComparer<T>のメソッドがSQLに変換されないという事実を処理します。

私は、それぞれの賛否両論を見る価値はあると思いますが、これはコメント以上のものがあります。

リッチのアプローチは、同じ最終結果を持つ別のクエリにクエリを書き換えます。それらのコードは、手作業でコード化されたSQLを使って効率的に行う方法を多かれ少なかれ発生させるはずです。

Ladislav'sは別個のものの前のポイントでデータベースを取り出して、メモリ内のアプローチが有効になります。

データベースはグルーピングとフィルタリングの種類が大きく異なるため、このケースではパフォーマンスが最も高くなります。このグループ化の前に起こっていることの複雑さは、Linq-to-entitiesが単一のクエリをうまく生成せず、むしろたくさんのクエリを生成し、その中のいくつかの作業をメモリ内で行うようなものであることがわかります。かなり厄介かもしれない。

通常、メモリ内のケースではグループ化の方が高価です(特に、ではなくAsList())。だから、すでに他のいくつかの要件のためにこの段階でそれをメモリに持っていこうとしているなら、それはより効果的です。

平等度の定義がデータベース内で利用可能なものとはまったく関係しないものであれば、唯一の選択肢になります。もちろん、これに基づいて同等性の定義を切り替えることができますIEqualityComparer<T>がパラメータとして渡されます。

私はここで一番いい選択であると言いたいのはリッチですが、ラディスラフと比較してラディスラフの賛否両論は勉強し検討する価値があります。

1

後期の答えが、あなたはより良い行うことができます: DALのオブジェクトが部分的であれば(それがある場合は通常、 DBオブジェクト)の場合、次のように拡張することができます。

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

そして、別名はオーバーロードなしで機能します。

ない場合、あなたはこのようにされたIEqualityComparerクラスを作成することができます。

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

そして再び、しかし、あなたが使用できないことに注意してください、これは命の恩人である任意の過負荷

関連する問題