Ali*_*Ali 8 c# linq expression dynamic in-clause
我想为EF 6.0中的sql IN子句创建一个动态linq表达式,代码为第一个approch.请注意,我是Expressions的新手.我想要的是
select * from Courses where CourseId in (1, 2, 3, 4)
//CourseId is integer
Run Code Online (Sandbox Code Playgroud)
正常的linq查询看起来像这样.但我想动态查询它
string[] ids = new string[]{"1", "2", "3", "4"};
var courselist = DBEntities.Courses.Where(c => ids.Contains(SqlFunctions.StringConvert((decimal?)c.CourseId)))
Run Code Online (Sandbox Code Playgroud)
有两种方法可以进行动态表达.
1)一种方法是遍历id并创建表达式
下面的代码将在调试视图中创建以下表达式
{f => ((StringConvert(Convert(f.CourseId)).Equals("23") Or StringConvert(Convert(f.CourseId)).Equals("2")) Or StringConvert(Convert(f.CourseId)).Equals("1"))}
Run Code Online (Sandbox Code Playgroud)
动态表达是
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);
Run Code Online (Sandbox Code Playgroud)
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);
Run Code Online (Sandbox Code Playgroud)
我收到以下错误
我在过去的4天里尝试过这个.我用谷歌搜索,但没有找到任何合适的解决方案.请帮我.
经过很多努力,我找到了解决问题的方法.我想实现这个SQL查询
select * from Courses where CourseId in (1, 2, 3, 4)
Run Code Online (Sandbox Code Playgroud)
使用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);
}
}
Run Code Online (Sandbox Code Playgroud)
使用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);
Run Code Online (Sandbox Code Playgroud)
我希望这可能对某些人有益