[英]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 我收到以下错误
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.. 所以,你的解决方案是......
Create array of IDs using for loop and then simply run the below query 使用for循环创建ID数组,然后只需运行以下查询
var courselist = DBEntities.Courses.Where(c => ids.Contains(c.CourseId))).ToList()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.