Generar dinámicamente consultas LINQ

Tenemos un objeto

public class SomeObject { public Name {get;set;} public City {get;set;} public State {get;set} //various other parameters. Let's say there's ~20 } 

¿Es posible crear dinámicamente nuevas consultas LINQ sin la recomstackción del código fuente? En cambio, los parámetros de consulta provienen de una estructura XML que se almacena y actualiza en la base de datos.

 var result = from i in someObj where //XML requests Name = 'Bob'...so append this where clause name = 'Bob' 

Se puede hacer esto?

Aquí hay una solución con árboles de expresiones:

 var param = Expression.Parameter(typeof(SomeObject), "p"); var exp = Expression.Lambda>( Expression.Equal( Expression.Property(param, "Name"), Expression.Constant("Bob") ), param ); var query = someObj.Where(exp); 

Sé que es mucho más complejo, pero esto puede ser útil en ocasiones.

Seguramente querrá echarle un vistazo a Dynamic Linq que le permitirá definir las condiciones de consulta como texto.

En cuanto a agregar condiciones dinámicamente, puede agregar condiciones a una consulta utilizando una syntax similar a;

 if(CategoryIsImportant) myQuery = myQuery.Where("CategoryId=2"); 

todos los cuales puedes (bastante fácilmente) codificar en un formato XML de tu elección.

Es difícil para mí contar en función de tu pregunta, pero en algunos casos no necesitas un Linq dynamic y simplemente puedes hacer esto …

 var result = from o in someObj where (Name == null || o.Name == Name) && (City == null || o.City == City) && (State == null || o.State == State) select o; 

Esto esencialmente evitará que los datos se filtren cuando el parámetro en cuestión sea nulo. Y todavía funciona bien gracias al comportamiento de cortocircuito en C #.

Quizás Dynamic Linq puede ayudarlo: Dynamic linq parte 1: Usar la biblioteca de consultas dinámicas de linq

 query = query.Where("Id = 123 And Age > 18"); 

O puede manipular su consulta Linq directamente:

 query = query.Where(x=>x.Id == 5); 

Creo que tendrás que cavar en Expression Trees . No he profundizado demasiado en esto, así que no puedo crear una muestra para usted, pero sí sé que puede usar Expression Trees para construir dinámicamente sus consultas y luego llamar a .Compile (en el código) para que pueda ejecutarse.

En realidad, aquí hay un enlace mejor Creación de consultas dinámicas con árboles de expresiones . Debería darte exactamente lo que quieres, y es bastante sucinto para lo que es. Esto debería actuar como un buen ejemplo para ti 🙂

Supongo que desea introducir filtros opcionales, según el contenido de su XML. Para continuar con el ejemplo de StriplingWarrior:

 var name = GetNameFromXml(); var city = GetCityFromXml(); var state = GetStateFromXml(); var result = someObj; if (name != null) result = result.Where(i => i.Name == name); if (city != null) result = result.Where(i => i.City == city); if (state != null) result = result.Where(i => i.State == state); 

De esta forma, estaría aplicando cualquier cantidad de filtros (de ninguno a los tres), dependiendo de lo que realmente se especifique en su XML.

Sí, en realidad es bastante fácil:

 var name = GetBobNameFromXml(); var result = someObj.Where(i => i.Name == name); 

También puede elegir si desea aplicar criterios por partes.

 var result = someObj; var name = xmlCriteria.Name; if(!string.IsNullOrEmpty(name)) { result = result.Where(i => i.Name == name); } // follow the same pattern for city, state, etc. 

Incluso podría usar un patrón que use un diccionario de funcion de criterio con clave de nombre, para evitar un grupo de sentencias if .

 foreach(var criterionPair in xmlCriteria) { var value = criterionPair.Value; result = result.Where(i => propGetters[criterionPair.PropertyName](i, value)); } 

Básicamente, hay mucho que puedes hacer a lo largo de estas líneas. Si desea una respuesta más específicamente adaptada a su situación, deberá proporcionar una pregunta más específica.