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



我想在 EF 6.0 中为 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)))
有两种

方法可以制作动态表达式.
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 我尝试的上述动态表达式是

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

我收到以下错误

  • LINQ to Entities 无法识别方法"System.String StringConvert(System.Nullable'1[System.Double])"方法,并且此当我使用第一种方法。我知道我不能将ToString与EF一起使用,这就是我使用SqlFunctions的原因,但它对我不起作用。
  • 参数"val"未绑定到使用第二种方法的指定 LINQ to 实体查询表达式中

我正在尝试过去 4 天。我用谷歌搜索了一下,但没有找到任何合适的解决方案。请帮助我。

经过一番挣扎,我找到了我的问题的解决方案。我想实现这个 sql 查询

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

使用 Linq 到实体,但我想动态地将 (1,2,3,4) 列表传递给 linq 查询。为此,我创建了一个扩展类。

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

我希望这可能对某些人有益

你见过类型

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

上述声明不会返回实际的课程列表。查询尚未执行。它只是返回智商。查询在实际调用 时执行。ToList() 方法在其上

所以,你的解决方案是..

  1. 使用 for 循环创建 ID 数组,然后简单地运行以下查询

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

相关内容

  • 没有找到相关文章

最新更新