2017-02-03 7 views
2

MongoDBデータベースには、それぞれが特定のタイプのオブジェクトを格納する少数のコレクションがあります。私は、次の定義のように、種類に応じて、特定のコレクションを操作するために、一般的な選択機能を実装しようとしています:MongoDB with C#:カスタム述語を持つ要素を見つける

object[] Select<T>(Func<T, bool> condition) 

例えば、オブジェクトの種類の一つはPersonクラスであるならば、私が実装します次

object[] Select<T>(Func<T, bool> condition) 
{ 
    if (typeof(T) == typeof(Person)) 
    { 
     Func<Person, bool> f = (Person p) => 
     { 
      return true; 
     }; 
     return this.collectionPersons.AsQueryable().Where(p=>f(p)).ToArray(); 
    } 
    else // ... 
} 

このコードはコンパイルが、私はそれを実行しようとすると、私は熟読した後

Additional information: Unsupported filter:   
Invoke(value(System.Func`2[Person,System.Boolean]), {document}). 

System.ArgumentExceptionを取得しますAPIドキュメント私は抽象的な種類のラムダ式を使用することはできませんが(上記の例のように)、 FilterDefinitionBuilderGt()Eq()など のようにサポートされているものだけがわかりますこれは、抽象的述語を持つコレクションを照会する可能性があります(MongoDB C#ドライバーが新しくなりました)。

答えて

1

もちろん、ラムダ式をパラメータとして使用できます。ドライバーはあなたの式を単純なフィルターにトラバレートしますが、すべての式を変換することはできませんが、可能であれば動作します。 私は本当にあなたがサンプルで何をしているか理解していない、あなたは

あなたの関数は、引数としてではないのFuncが、発現すべきであるあなたの状態を使用しないでください。

public static T[] Select<T>(IMongoCollection<T> collection, 
          Expression<Func<T, bool>> condition) 
{ 
    if (typeof(T) == typeof(Person)) 
    { 
     return collection.AsQueryable().Where(condition).ToArray(); 
    } 
    return null; 
} 

そして、あなたがそれを呼び出すことができます表現:

var res = Select(this.collectionPersons, x => x.FirstName == "a3"); 

あなただけのすべての項目を照会する場合は、あなたのようにそれを行うことができ、同じように見えるよう:

return this.collectionPersons.Find(p=>true).ToArray(); 

そして、あなたはusings内のすべての名前空間を言及する必要があります。

using System; 
using System.Collections.Generic; 
using System.Linq.Expressions; 
using System.Linq; 
using MongoDB.Driver; 
using MongoDB.Driver.Linq; 
+0

ありがとうございましたMaksim、私は式の代わりに式を実装しようとしました。次のエラーが表示されます。 MongoDB.Driver.Linq.IMongoQueryable 'には' Where 'の定義が含まれていません。また、最適な拡張メソッドオーバーロード' System.Linq.Queryable.Where (System.Linq.IQueryable 、System.Linq.Expressions.Expression >) 'に無効な引数がいくつかあります。 私は自然にこのようにすべての項目を照会するつもりはない、 'return true;'とにかくうまくいかなかったもっとも単純なケースでした。 –

+0

私はこれを試してみましたが、この方法で私は答えました(私はそれを少し更新しました)私は自分のコレクションに問い合わせることができました。 –

+0

@AlexKonnenおそらく、いくつかのusingステートメントがありませんか? –

0

私のエラーは、私が述語と呼ばれる方法にありました。以下 は、それが動作する例です:あなたは述語によって人物のサブセットを必要とする場合

public object[] SelectByPredicate<T>(Func<T, bool> predicate) 
{ 
    if (typeof(T) == typeof(Person)) 
    { 
     Func<Person, bool> f = (Person p) => 
     { 
      T t = (T)Convert.ChangeType(p, typeof(T)); 
      return predicate(t); 
     }; 

     return this.SelectPersonsByPredicate(f); 
    } 
    else if (typeof(T) == typeof(Pet)) 
    { 
     Func<Pet, bool> f = (Pet p) => 
     { 
      T t = (T)Convert.ChangeType(p, typeof(T)); 
      return predicate(t); 
     }; 

     return this.SelectPetsByPredicate(f); 
    } 
    else 
    { 
     throw new NotSupportedException("Type not supported"); 
    } 
} 

private Person[] SelectPersonsByPredicate(Func<Person, bool> predicate) 
{ 
    return this.collectionPersons.AsQueryable().Where(predicate).ToArray(); 
} 

private Pet[] SelectPetsByPredicate(Func<Pet, bool> predicate) 
{ 
    return this.collectionPets.AsQueryable().Where(predicate).ToArray(); 
} 

次に、あなただけの

object[] personsSelected = db.SelectByPredicate<Person>(p=>p.Name.Contains("Theo")); 

ような何かを書くことは、私は、認める、非常にエレガントではありませんT[]の代わりにobject[]を返しますが、すべての実用的な目的では問題ありません。 誰かがより良い方法を知っているなら、私は興味があります。

関連する問題