0

以下の方法をOR演算に使用すると、重複したレコードが返されます。カスタムIEqualityComparerを指定する必要がありますか?単純なdistinct()は機能しません

internal static IQueryable<T> FilterEntity<T>(filters filters, IQueryable<T> entities)
    {
        if (filters.groupOp == "AND")
            foreach (var rule in filters.rules)
                entities = entities.Where<T>(
                    rule.field, rule.data,
                    (WhereOperation)StringEnum.Parse(typeof(WhereOperation), rule.op)
                    );
        else
        {
            //Or
            IQueryable<T> temp = (new List<T>()).AsQueryable();
            foreach (var rule in filters.rules)
            {
                var t = entities.Where<T>(
                    rule.field, rule.data,
                    (WhereOperation)StringEnum.Parse(typeof(WhereOperation), rule.op)
                    );

                    temp = temp.Concat<T>(t).AsQueryable();
            }
            entities = temp;
        }
        return entities;
    }

以下の@usrからの提案の後に編集-これはSQLプロファイラーで正しいクエリを提供します(明確に)が、これは複雑すぎるように見え始めます-私はよりクリーンなソリューションのようです

    internal static IQueryable<T> FilterEntity<T>(filters filters, IQueryable<T> entities)
    {
        if (filters.groupOp == "AND")
            foreach (var rule in filters.rules)
                entities = entities.Where<T>(
                    rule.field, rule.data,
                    (WhereOperation)StringEnum.Parse(typeof(WhereOperation), rule.op)
                    );
        else
        {
            //Or
            var t1 = entities.Where<T>(filters.rules[0].field,filters.rules[0].data,
                (WhereOperation)StringEnum.Parse(typeof(WhereOperation),filters.rules[0].op)
                );
            for (int i = 1; i<filters.rules.Count(); i++)
            {

                var t = t1.Where<T>(filters.rules[i].field, filters.rules[i].data,
                (WhereOperation)StringEnum.Parse(typeof(WhereOperation), filters.rules[i].op)
                );
              t1.Concat<T>(t).AsQueryable();
            }
           entities  = t1;
        }
        return entities.Distinct<T>();
    }
4

2 に答える 2

1

これはまたはとは関係ありませDistinct()IEqualityComparer。これは、変更されたクロージャの落とし穴です。つまり、ループ変数ruleをループ本体にコピーする必要があります。

foreach (var rule in filters.rules)
{
    var rule1 = rule;
    // work with rule1 only.

これを行うことで、Usrのアドバイスに従うことができます。

IQueryable<T> temp = null;
    ....
    foreach (var rule in filters.rules)
    {
        var rule1 = rule;
        var t = entities.Where<T>(rule1.field, rule1.data,
            (WhereOperation)StringEnum.Parse(typeof(WhereOperation), rule1.op));

            if (temp == null)
                temp = t;
            else
                temp = temp.Union(t); // Union!!
    }
}
return temp;

それであなたの問題は解決するのだろうか。Union(これは暗黙的です)の使用に注意してくださいDistinct。それがあなたの問題を解決しない場合、私は私たちに見えない(例えばあなたのWhereOperation)いくつかのコードが干渉していると思います。

于 2012-06-05T08:53:10.967 に答える
1

List<T>クエリを開始するためにから始めないでください。最初の「t」から始めます。そうすれば、サーバーで実行されているクエリを1つだけ取得できます。明確な結果を得るには、Concatの代わりにUnionを使用してください。

于 2012-06-05T18:52:29.550 に答える