我想在EF 6.0中为sql IN子句创建一个动态linq表达式,代码为第一个approch。请注意,我是Expressions的新手。我想要实现的是
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)))
有两种方法可以进行动态表达
1)一种方法是循环通过id并使表达式为
以下代码将在调试视图中创建以下表达式
{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
我试过的动态表达式是
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);
我收到以下错误
我在过去4天尝试这个。我用谷歌搜索,但没有找到任何合适的解决方案。请帮帮我。
答案 0 :(得分:8)
经过多次努力,我找到了解决问题的方法。 我想实现这个SQL查询
select * from Courses where CourseId in (1, 2, 3, 4)
使用Linq to Entities,但我想将(1,2,3,4)列表动态传递给linq查询。我为此创建了一个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);
}
}
使用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);
我希望这可能对某些人有益
答案 1 :(得分:0)
var courselist = DBEntities.Courses.Where(c => ids.Contains(c.CourseId)))
以上声明不会返回实际的课程列表。查询尚未执行。它只返回IQuereable。当您实际调用.ToList()方法
时执行查询所以,你的解决方案是......
使用for循环创建ID数组,然后只需运行以下查询
var courselist = DBEntities.Courses.Where(c => ids.Contains(c.CourseId))).ToList()