2

私は文字列を持っています:

strCheckedCategories = "2;"

アイテム ID が 1 から 21 の SharePoint リストを表す EntityList:

EntityList<VendorSearchesItem> vendorSearches = 
    dataContext.GetList<VendorSearchesItem>("Vendor Searches");

"Vendor Searches" リストに結合された 2 つの SharePoint リストからフィールドを返す LINQ クエリ:

var vendorSearchesQuery = (from s in vendorSearches
                           orderby s.VendorID.Title
                           select new
                           {
                               Vendor = s.VendorID.Title,
                               Website = s.VendorID.VendorWebsite,
                               VendorID = s.VendorID.Id,
                               SearchType = s.SearchTypeID.Title,
                               SearchTypeId = s.SearchTypeID.Id
                           });

アイテム ID がリストにあるアイテムのみを返す別の LINQ クエリ:

var q2 = from m2 in vendorSearchesQuery 
         where strCheckedCategories.Contains(m2.SearchTypeId.ToString())
         select m2

問題は、クエリが ID 2 (目的の結果) のアイテムを返すだけでなく、ID 12、20、および 21 のアイテムも返すことです。どうすれば修正できますか?

4

5 に答える 5

4

したがって、基本的に、ここでやりたいことはIN、フィールドに一連の値を指定し、その列の値がそのセットにある行が必要な句を持つことです。

CAML には実際に使用できる IN 句がありますが、残念ながら LINQ to Sharepoint には IN 句を生成する手段がありません。クエリ プロバイダーでサポートされていないだけです。

適切な演算子を使用するのではなく、文字列の比較を行うことで、この問題を回避するためにちょっとしたハックを使用しようとしており、すべての操作を文字列化するという落とし穴に陥っています。それは単にタスクに適していません。

前述したように、LINQ to SharePoint で IN を使用することはできないため、LINQ を使用せずに CAML を手動で構築し、標準のサーバー オブジェクト モデルを使用して実行するという方法があります。しかし、それは楽しいことではありません。

できることは、一連の OR チェックを行うことです。その列の値が、セット内のすべての値の最初の値であるか、2 番目であるか、3 番目であるかなどがわかります。これは実質的に IN 句と同じですが、はるかに冗長です。

ここで、未知の数の比較をどのように OR するかという問題が生じます。AND の場合は簡単Whereです。ループ内で呼び出すだけで、それらの N 句の AND になります。

代わりに、式を使用する必要があります。動的な数の OR 句の式ツリーを自分で手動で作成すると、クエリ プロバイダーはそれを問題なく解析できます。

指定されたプロパティ値が値のセットに含まれるすべてのアイテムにクエリをフィルター処理する新しいメソッド はWhereIn、クエリ、使用しているプロパティのプロパティ セレクター、および値のセットを受け入れる必要があります。比較対象は同じタイプ。それができたら、プロパティ アクセスと各キー値の比較式を作成し、それらの式すべてを OR するだけです。

public static IQueryable<TSource> WhereIn<TSource, TKey>(
    this IQueryable<TSource> query,
    Expression<Func<TSource, TKey>> propertySelector,
    IEnumerable<TKey> values)
{
    var t = Expression.Parameter(typeof(TSource));
    Expression body = Expression.Constant(false);
    var propertyName = ((MemberExpression)propertySelector.Body).Member.Name;

    foreach (var value in values)
    {
        body = Expression.OrElse(body,
            Expression.Equal(Expression.Property(t, propertyName),
                Expression.Constant(value)));
    }

    return query.Where(Expression.Lambda<Func<TSource, bool>>(body, t));
}

これを呼び出すには、クエリ、フィルタリングするプロパティ、および値のコレクションが必要です。

var q2 = vendorSearchesQuery.WhereIn(vendor => vendor.SearchTypeId
    , strCheckedCategories.Split(';'));

そして出来上がり。

そのまま動作することを期待していますが、 の前にを呼び出す必要がある場合があります。すでにマップされている では正しく機能しない場合があります。WhereIn SelectSearchTypeId

于 2013-10-11T16:42:19.173 に答える
1

おそらく正規表現を使用する必要がありますが、より単純なソリューションが必要な場合は、文字列検索を避け、それらの文字列を配列に分割します。

string strCheckedCategories = "2;4;5;7;12;16;17;19;20;21;";
string[] split = strCheckedCategories.Split(';');

末尾のセミコロン区切り文字の配列に空のエントリが作成されます。私はそれをチェックし、これが問題である場合は削除します:

strCheckedCategories.TrimEnd(';');

where最後に、句を変更できます。

where split.Contains(m2.SearchTypeId.ToString())

リストが非常に大きい場合は、strCheckedCategories を整数のリストに解析して、文字列ではなく整数を比較する価値があるでしょう。

int[] split = strCheckedCategories.Split(';').Select(x => Convert.ToInt32(x)).ToArray();

次に、より迅速な等式を実行できます。

where split.Contains(m2.SearchTypeId)
于 2013-10-11T16:29:20.640 に答える
0
var q2 = from m2 in vendorSearchesQuery 
         where strCheckedCategories.Split(';').Contains(m2.SearchTypeId.ToString())
         select m2
于 2013-10-11T16:28:40.360 に答える
0
var q2 = from m2 in vendorSearchesQuery 
         where strCheckedCategories.Contains(";" + m2.SearchTypeId + ";")
         select m2

また、strCheckedCategories常に で終わり、;で始まる必要があります。;たとえば;2;;2;3;, ...

: このトリックは、SearchTypeId常に含まれてはならない場合にのみ機能します;\nチェックしたカテゴリをリストまたは配列に保存するなど、別の種類のセパレータを使用する必要があると思いますそれがより標準的な方法です。

于 2013-10-11T16:31:03.777 に答える