简体   繁体   English

使用Entity框架的sql IN子句的动态linq查询表达式树

[英]Dynamic linq query expression tree for sql IN clause using Entity framework

I want to create a dynamic linq expression for sql IN clause in EF 6.0 with code first approch. 我想为EF 6.0中的sql IN子句创建一个动态linq表达式,代码为第一个approch。 Note that i am new to Expressions. 请注意,我是Expressions的新手。 What i want to achive is 我想要的是

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

The normal linq query looks like this. 正常的linq查询看起来像这样。 But i want to query it dynamically 但我想动态查询它

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

There are two ways to make dynamic expression. 有两种方法可以进行动态表达。
1) one ways is to loop through ids and make expressions 1)一种方法是循环id并制作表达式
The below code will create the following expression in debug view 以下代码将在调试视图中创建以下表达式

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

Dynamic Expression is 动态表达是

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) The 2nd way that i tried (debug view) 2)我试过的第二种方式(调试视图)

{f => val.Contains("23")} //val is parameter of values above
The dynamic expression for above that i tried is 我试过的上面的动态表达是

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 get the following errors 我收到以下错误

  • LINQ to Entities does not recognize the method 'System.String StringConvert(System.Nullable`1[System.Double])' method, and this method cannot be translated into a store expression when i use the first methodology. LINQ to Entities无法识别方法'System.String StringConvert(System.Nullable`1 [System.Double])'方法,并且当我使用第一种方法时,此方法无法转换为商店表达式 I know i can't use ToString with EF thats why I used SqlFunctions but it is not working for me. 我知道我不能在EF中使用ToString,这就是为什么我使用SqlFunction但它不适合我。
  • The parameter 'val' was not bound in the specified LINQ to Entities query expression using 2nd methodology 使用第二种方法,参数“val”未绑定在指定的LINQ to Entities查询表达式中

I am trying this from last 4 days. 我在过去的4天里尝试过这个。 I googled it but didn't find any suitable solution. 我用谷歌搜索,但没有找到任何合适的解决方案。 Please help me. 请帮我。

After a lot of struggle I found solution to my question. 经过很多努力,我找到了解决问题的方法。 I want to achieve this sql query 我想实现这个SQL查询

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

Using Linq to Entities, but I want to pass in(1,2,3,4) list dynamically to linq query. 使用Linq to Entities,但我想将(1,2,3,4)列表动态传递给linq查询。 I created an Extension class for that purpose. 我为此创建了一个Extension类。

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);
   }
}

Use of LinqExtensions 使用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);

I hope this might be beneficial for some one 我希望这可能对某些人有益

have you seen the type of 你见过的那种吗?

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

above statement would not return actual list of courses. 上述声明不会返回实际的课程列表。 The query is not executed yet. 查询尚未执行。 It just returns IQuereable. 它只返回IQuereable。 The query is executed when you actually call .ToList() method on it 当您实际调用.ToList()方法时执行查询

so, your solution is.. 所以,你的解决方案是......

  1. Create array of IDs using for loop and then simply run the below query 使用for循环创建ID数组,然后只需运行以下查询

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM