web-dev-qa-db-ja.com

単一のLINQステートメントで.Selectおよび.Whereを使用する

LINQを使用して特定のテーブルから個別のIDを収集する必要があります。キャッチは、設定した要件のみに基づいて結果をフィルタリングするWHEREステートメントも必要です。 LINQをそれほど使用する必要があるのは比較的新しいですが、次のコードを多少使用しています。

private void WriteStuff(SqlHelper db, EmployeeHelper emp)
{
    String checkFieldChange;
    AnIList tableClass = new AnIList(db, (int)emp.PersonId);
    var linq = tableClass.Items
        .Where(
           x => x.UserId == emp.UserId 
             && x.Date > DateBeforeChanges 
             && x.Date < DateAfterEffective 
             && (
                     (x.Field == Inserted)
                  || (x.Field == Deleted)))
                )
             ).OrderByDescending(x => x.Id);

    if (linq != null)
    {
        foreach (TableClassChanges item in linq)
        {
            AnotherIList payTxn = new AnotherIList(db, item.Id);
            checkFieldChange = GetChangeType(item.FieldName);

            // Other codes that will retrieve data from each item 
            // and write it into a text file
        }
    }
}

Var linqに.Distinctを追加しようとしましたが、重複したアイテムが返されています(同じIDを持つことを意味します)。多くのサイトを読んで、.Selectをクエリに追加しようとしましたが、代わりに.Where句が壊れています。他の記事では、値を取得してvarに配置する方法によってクエリが何らかの形で異なる場合があります。また、.GroupByを使用しようとしましたが、IDをキーとして使用すると、「少なくとも1つのオブジェクトがIComparableを実装する必要があります」というメッセージが表示されます。

クエリは実際に機能し、必要な仕様で列からデータを出力することはできますが、.Distinctを機能させることができないようです(実際に不足しているのはこれだけです)。 1つの異なる呼び出しをトリガーする2つの変数を作成し、ネストされたforeachを使用して値が一意であることを確認しようとしましたが、パフォーマンスへの影響を収集する数千のレコードが多すぎます。

要件にIEnumerableをオーバーライドまたは使用する必要があるかどうかも不明であり、簡単な方法がある場合、または.Selectと.Whereの両方を機能させることができる場合に備えて、質問をすることを考えましたただ一つの声明で?

25
robertviper08

Enumerable.Distinct あなたのタイプで動作するように、IEquatable<T>およびEqualsおよびGetHashCodeの適切な定義を提供します。それ以外の場合は、デフォルトの実装を使用します:参照の等価性の比較(参照型を使用していると仮定)。

マニュアルから:

Distinct(IEnumerable)メソッドは、重複する値を含まない順序付けられていないシーケンスを返します。デフォルトの等値比較子Defaultを使用して値を比較します。

デフォルトの等値比較子Defaultは、IEquatableジェネリックインターフェイスを実装する型の値を比較するために使用されます。カスタムデータ型を比較す​​るには、このインターフェイスを実装し、その型に対して独自のGetHashCodeおよびEqualsメソッドを提供する必要があります。

あなたの場合、IDを比較するだけでよいように見えますが、2つのオブジェクトが「同じ」という意味に応じて、他のフィールドも比較することもできます。

また、 DistinctBy from morelinq の使用を検討することもできます。

これはLINQ to Objectsのみであることに注意してください。しかし、私はそれがあなたが使っているものだと思います。

さらに別のオプションは、GroupByFirstを結合することです:

 var query = // your query here...
    .GroupBy(x => x.Id)
    .Select(g => g.First());

これは、たとえばLINQ to SQLでも機能します。

11
Mark Byers

Select()の後または前にWhere()を追加しましたか?

同時実行ロジックのため、後で追加する必要があります。

_ 1 Take the entire table  
 2 Filter it accordingly  
 3 Select only the ID's  
 4 Make them distinct.  
_

最初に選択を行う場合、他のすべての属性は既に編集されているため、Where句にはID属性のみを含めることができます。

更新:明確にするために、この演算子の順序は機能するはずです。

_db.Items.Where(x=> x.userid == user_ID).Select(x=>x.Id).Distinct();
_

おそらく最後に.toList()を追加したいが、それはオプションです:)

38
Flater

2つの異なるオブジェクトを比較しようとしているため、最初にIEqualityComparerインターフェイスを実装する必要があります。 IEqualityComparerの明確で単純な実装を使用する単純なコンソールアプリケーションのサンプルコードを次に示します。

 class Program
{
    static void Main(string[] args)
    {
        List<Test> testData = new List<Test>()
        {
            new Test(1,"Test"),
            new Test(2, "Test"),
            new Test(2, "Test")
        };

        var result = testData.Where(x => x.Id > 1).Distinct(new MyComparer());
    }
}

public class MyComparer : IEqualityComparer<Test>
{
    public bool Equals(Test x, Test y)
    {
        return x.Id == y.Id;
    }

    public int GetHashCode(Test obj)
    {
        return string.Format("{0}{1}", obj.Id, obj.Name).GetHashCode();
    }
}


public class Test
{
    public Test(int id, string name)
    {
        this.id = id;
        this.name = name;
    }

    private int id;

    public int Id
    {
        get { return id; }
        set { id = value; }
    }
    private string name;

    public string Name
    {
        get { return name; }
        set { name = value; }
    }
}

それがお役に立てば幸いです。

2
ScorpiAS

_IEqualityComparer<T>_を.Distinct()に渡しましたか?

このようなもの:

_internal abstract class BaseComparer<T> : IEqualityComparer<T> {
    public bool Equals(T x, T y) {
        return GetHashCode(x) == GetHashCode(y);
    }

    public abstract int GetHashCode(T obj);
}

internal class DetailComparer : BaseComparer<StyleFeatureItem> {
    public override int GetHashCode(MyClass obj) {
        return obj.ID.GetHashCode();
    }
}
_

使用法:

_list.Distinct(new DetailComparer())
_
1
Malmi