una tipos tipo solo sintaxis puede primitivos framework expresiones este enumeración entidad ejemplos contexto consultas consulta construir complejo comandos admiten c# linq dynamic expression in-clause

tipos - sintaxis linq c#



Árbol de expresiones dinámicas de consulta de linq para la cláusula IN de SQL utilizando el marco Entity (2)

Quiero crear una expresión dinámica de linq para la cláusula sql IN en EF 6.0 con el primer acercamiento del código. Tenga en cuenta que soy nuevo en Expressions. Lo que quiero lograr es

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

La consulta de linq normal se ve así. Pero quiero consultarlo dinámicamente

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

Hay dos formas de hacer una expresión dinámica.
1) una forma es recorrer los identificadores y hacer expresiones
El siguiente código creará la siguiente expresión en la vista de depuración

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

La expresión dinámica es

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) La 2da forma en que lo intenté (vista de depuración)

{f => val.Contains("23")} //val is parameter of values above
La expresión dinámica para arriba que probé es

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

Recibo los siguientes errores

  • LINQ to Entities no reconoce el método ''System.String StringConvert (System.Nullable`1 [System.Double])'', y este método no se puede traducir a una expresión de tienda cuando utilizo la primera metodología. Sé que no puedo usar ToString con EF por eso utilicé SqlFunctions, pero no funciona para mí.
  • El parámetro ''val'' no estaba enlazado en la expresión de consulta LINQ to Entities especificada usando la 2da metodología

Estoy intentando esto de los últimos 4 días. Busqué en Google pero no encontré ninguna solución adecuada. Por favor, ayúdame.


¿Has visto el tipo de

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

la declaración anterior no devolvería la lista real de cursos. La consulta no se ejecutó aún. Simplemente devuelve IQuereable. La consulta se ejecuta cuando realmente se llama al método .ToList ()

Entonces, tu solución es ...

  1. Cree una matriz de ID usando for loop y luego simplemente ejecute la consulta siguiente

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


Después de mucha lucha, encontré la solución a mi pregunta. Quiero lograr esta consulta sql

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

Usando Linq para Entidades, pero quiero pasar la lista (1,2,3,4) dinámicamente a la consulta de linq. Creé una clase de extensión para ese propósito.

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

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

Espero que esto sea beneficioso para alguien