2011-12-20 8 views
0

現在、SQLにIn文を作成するコードがいくつかあります。私は表現を作って、それを返します。式<Func<T,bool>>を新しい式のパラメータとして使用する

value(generic(list[T])).Contains(x => x.Id) 

これは正常に動作します。したがって、オブジェクトのリストがある場合は正常です。

public class ObjectToSearch 
{ 
    public int IdToSearchOn {get;set;} 
} 

ids 1,2,3を検索したいのですが、うまくいきます。私のSQLクエリは素晴らしいです。

今、私はネストされたオブジェクトのリストを検索する必要があります。

public class ParentObjectToSearch 
{ 
    public IEnumerable<ObjectToSearch> Objects {get;set;} 
} 

ので、いくつかのコードを見て私は、私はこの方法を適用し、一部またはすべての呼び出しをラップすることができ考え出し、それが働くだろう(How do I create an expression tree calling IEnumerable<TSource>.Any(...)?)を発見しました。私が実際にデータベースに対してテストするまで、これは素晴らしいものでした。

' System.Collections.Generic.ICollection`1 'の要素を比較できません。プリミティブ型(Int32、String、Guidなど)とエンティティ型のみがサポートされています。

var collectionType = GetIEnumerableImpl(forCollection.Type); 

Type elementType = collectionType.GetGenericArguments()[0]; 

MethodInfo method = BaseFilter.GetType().GetMethod("FilterWith"); 

MethodInfo genericMethod = method.MakeGenericMethod(new[] { elementType }); 

return (genericMethod.Invoke(BaseFilter, null) as LambdaExpression); 

FilterWithは、私は私の表現を取り戻すのを期待して、元のフィルタに呼んでいる方法です。だから、私の内側の式が外側の式と組み合わされたときに間違って評価されているように見えます。私が基本的に目指しているのは(私は)信じています。

x => x.Collection.Contains(y => new { 1, 3, 3}.Contains(y.Id)); 

私は別に内部フィルタリングをテストする場合、それは正常に動作しますので、私はそれが私が要素を組み合わせしようとしている、と私は試してみて、使用が代わりにいずれか、またはすべての含まれている場合、私はまだ入手どれだけだと仮定同じエラー。

タグにEntity Frameworkを配置しました。これは、エンティティセットに対して式として評価されているため、誰かがこれを実行した経験がある可能性があります。

更新夜を考えて、私はより良い質問があると思います。

Where式を作成してビルドするにはどうすればいいですか。

X => x.Collection.Where(Y =>新規[] {1、3} .Contains(y.Id)))(カウント> 0

+0

フィルタを手動で組み立ててみましたか(つまり、リフレクションではない)、それが機能することを確認しましたか?あなたは完成したフィルターを質問に投稿し、それのどの部分がうまくいっていないのかコメントしてください。 – dasblinkenlight

+0

私はエラーを取り戻し続けます。 'System.Collections.Generic.ICollection'1型の要素を比較できません。プリミティブ型(Int32、String、Guidなど)とエンティティ型のみがサポートされています。私が評価している内部表現が実際にエラーの原因になっていると私は信じています。それはx =>値(System.Collections.Generic.List'1 [System.Int32]).Contains(Convert(x.Id)))であるようです) – Hammerstein

答えて

1

元のエラーは、実際に私は反対ヌルのチェックを行うようにしようとしていたことに起因していましたコレクションは、まあ、それは確かにSQLで行うことはできません。

次に、AnyとAllはSQL式に変換できません。

Expression<Func<TEntity, bool>> result = Expression.Lambda<Func<TEntity, bool>>(
      Expression.GreaterThan(
       Expression.Call(CountMethod(elementType), 
           Expression.Call(WhereMethod(elementType), 
               theCollectionWeAreSearching, 
               filter)), 
       Expression.Constant(0)), param); 

elementTypeは、コレクション内の要素の型です。フィルタは私のリストをテストする式です。 CountメソッドとWhereメソッドは次のように取得されました。

public MethodInfo GetMethodFromEnumerable(string methodName, params Func<MethodInfo, bool>[] filters) 
     { 
      var methods = typeof(Enumerable) 
       .GetMethods(BindingFlags.Static | BindingFlags.Public) 
       .Where(mi => mi.Name == methodName); 

      methods = filters.Aggregate(methods, (current, filter) => current.Where(filter)); 

      return methods.First(); 
     } 

     public MethodInfo WhereMethod(Type collectionType) 
     { 
      // Get the Func<T,bool> version 
      var getWhereMethod = GetMethodFromEnumerable("Where", 
            mi => mi.GetParameters()[1].ParameterType.GetGenericArguments().Count() == 2); 

      return getWhereMethod.MakeGenericMethod(collectionType); 
     } 

     public MethodInfo CountMethod(Type collectionType) 
     { 
      var getCountMethod = GetMethodFromEnumerable("Count"); // There can be only one 

      return getCountMethod.MakeGenericMethod(collectionType); 
     } 

私は何度も新しいコードが導入されたので、何もないところで問題を探すようになりました。

1

私はここでの問題は、ということであると思いますEFは、あなたがObjectToSearchをデータベースに送ってそれを比較するように求めていると考えています。

// This won't work because it is asking EF to generate a SQL value equivalent to some class instance 
((List<ParentObjectToSearch>)someList).Contains(x => x.Id) 

私はそれはのように思えるsure-することはできません。言い換えれば、私はあなたには、いくつかのフィールドの任意の値は明らかに動作しませんこれは、いくつかのクラスのインスタンスに等しいかどうかをSQL Serverを求めていると思いますこの使用の具体的な例が質問から欠落しています。これが右に聞こえる場合は、クエリを生成する前に検索したい値のセットを平坦化してみてください。

// Assuming var outerList = some List<ParentObjectToSearch> 
// this un-nests the IDs, so they can be sent to SQL Server as integers 
// (which can be converted to a CONTAINS or = clause) 
var listOfUnNestedIDs = outerList.SelectMany(po=>po.Objects.Select(o=>o.IdToSearchOn)); 
関連する問題