2013-10-23 16 views
7

EF 6.0のsql IN句の動的linq式を、最初のapprochコードで作成します。私は式が初めてであることに注意してください。私は何をしたいですか?Entityフレームワークを使用したSQL IN句の動的linqクエリ式ツリー

select * from Courses where CourseId in (1, 2, 3, 4) 
//CourseId is integer 

通常のlinqクエリは次のようになります。しかし、私はそれを動的に照会したいです

string[] ids = new string[]{"1", "2", "3", "4"}; 
var courselist = DBEntities.Courses.Where(c => ids.Contains(SqlFunctions.StringConvert((decimal?)c.CourseId))) 

動的表現を行うには2通りの方法があります。
1)1つの方法)第二の方法IDSをループしていると表現
次のコードは、デバッグビューで、次の式

{f => ((StringConvert(Convert(f.CourseId)).Equals("23") Or StringConvert(Convert(f.CourseId)).Equals("2")) Or StringConvert(Convert(f.CourseId)).Equals("1"))} 

ダイナミック式が

var param = Expression.Parameters(typeof(Course), "f") 
MemberExpression property = Expression.PropertyOrField(param, "CourseId");     
MethodInfo mi = null; 
MethodCallExpression mce = null; 
if (property.Type == typeof(int)) 
{ 
    var castProperty = Expression.Convert(property, typeof(double?)); 
    var t = Expression.Parameter(typeof(SqlFunctions), "SqlFunctions"); 
    mi = typeof(SqlFunctions).GetMethod("StringConvert", new Type[] { typeof(double?) }); 
    mce = Expression.Call(null,mi, castProperty); 
} 
mi = typeof(string).GetMethod("Equals", new Type[]{ typeof(string)});    
BinaryExpression bex = null; 
if (values.Length <= 1) 
{ 
    return Expression.Lambda<Func<T, bool>>(Expression.Call(mce, mi,  Expression.Constant(values[0]), param)); 
} 
//var exp1 = Expression.Call(mce, mi, Expression.Constant(values[0])); 
for (int i = 0; i < values.Length; i++) 
{    
    if (bex == null) 
    { 
     bex = Expression.Or(Expression.Call(mce, mi, Expression.Constant(values[i])), Expression.Call(mce, mi, Expression.Constant(values[i + 1]))); 
     i++; 
    } 
    else    
     bex = Expression.Or(bex, Expression.Call(mce, mi, Expression.Constant(values[i]))); 

}//End of for loop 
return Expression.Lambda<Func<T, bool>>(bex, param); 

2で作成されます作ります私は試してみました(デバッグビュー)

{f => val.Contains("23")} //val is parameter of values above
ダイナミックexpr私が試したことが、上記のためのessionは

var param = Expression.Parameters(typeof(Course), "f") 
MemberExpression property = Expression.PropertyOrField(param, "CourseId"); 
var micontain = typeof(Enumerable).GetMethods().Where(m => m.Name == "Contains" && m.GetParameters().Length == 2).Single().MakeGenericMethod(typeof(string)); 
var mc = Expression.Call(micontain, Expression.Parameter(values.GetType(), "val"), Expression.Constant("2"));//NOTE: I haven't use CourseId for now as i am getting conversion error 
return Expression.Lambda<Func<T, bool>>(mc, param); 

あるI取得するには、次のエラー

  • 方法「を認識しないエンティティへのLINQ可能System.String StringConvert(System.Nullable`1 [System.Double] ) 'メソッドであり、この メソッドは、最初の方法で を使用すると、ストア式に変換できません。なぜ私はSqlFunctionsを使用したのか、それは私のために働いていないthatsのEFとToStringを使用することはできません知っている。
  • パラメータ「ヴァル」がエンティティに指定されたLINQにバインドされていなかったが、私は最後の4日から、これをしようとしています

第二の方法論を用いた発現を問い合わせます。私はそれをgoogledしかし、適切な解決策を見つけることができませんでした。私を助けてください。

答えて

8

闘争の多くの後、私は私の質問への解決策を見つけました。 私はエンティティへのLINQを使用して、このSQLクエリ

select * from Courses where CourseId in (1, 2, 3, 4) 

を達成したいが、私は、LINQクエリに動的で(1,2,3,4)のリストを渡したいです。その目的のためにExtensionクラスを作成しました。 LinqExtensions

var pred = LinqExtensions.False<Course>(); //You can chain In function like LinqExtensions.False<Course>().In<Course, int>("CourseId", inList); 
var inList= new List<int>(){1, 2, 3}; //Keep in mind the list must be of same type of the Property that will be compared with. In my case CourseId is integer so the in List have integer values 
pred =pred.In<Course, int>("CourseId", inList); //TValue is int. As CourseId is of type int. 
var data = MyEntities.Courses.Where(pred); 

public static class LinqExtensions 
{ 
    public static Expression<Func<T, bool>> False<T>() { return f => false; } 
    public static Expression<Func<T, bool>> In<T, TValue>(this Expression<Func<T, bool>> predicate,string propertyName, List<TValue> values) 
    {    
      var param = predicate.Parameters.Single(); 
      MemberExpression property = Expression.PropertyOrField(param, propertyName);    
      var micontain = typeof(List<TValue>).GetMethod("Contains");    
      var mc = Expression.Call(Expression.Constant(values), micontain, property); 
      return Expression.Lambda<Func<T, bool>>(mc, param); 
    } 
} 

使用して、私はまあ、私はそれがIQuerable実際のないリストを返すことを知って、これはいくつかのいずれか

0

あなたはコースの実際のリストを返しません声明上記

var courselist = DBEntities.Courses.Where(c => ids.Contains(c.CourseId))) 

の種類を見てきました。クエリはまだ実行されていません。それはただIQuereableを返します。クエリは、あなたはそれが

ので、あなたのソリューションがある上、実際にループのために使用したIDの配列を作成します。..

  1. を.ToList()メソッドを呼び出した後、単純に以下のクエリを実行したときに実行される

  2. var courselist = DBEntities.Courses.Where(c => ids.Contains(c.CourseId))).ToList()

+0

のために有益であるかもしれない願っています。あなたは私の質問を得ていませんでした。私は同じことをしたいids.Contains(c.CourseId)を使用して動的に式ツリー – Ali

関連する問題