Buscar a través de la cláusula Where en LINQ, usando propiedades dinámicas

Básicamente estoy tratando de construir una consulta, y no sé por qué Microsoft hizo esto tan difícil en Entity Framework y LINQ. Tengo varios parámetros STRINGS. Entonces, si ves una variable, asume que es una cadena que se pasa desde algún lugar.

users = this.entities.tableUsers .Where(searchfield+" LIKE %@0%", search) .OrderBy(x => x.GetType().GetProperty(order_by).GetValue(x, null).ToString()) .Skip(Convert.ToInt32(limit_begin)) .Take(Convert.ToInt32(limit_end)) .ToList(); 

Mi pregunta es qué poner dentro de la función “Where ()” en LINQ.

Quiero buscar un campo con la cadena “campo de búsqueda”, para el valor .contains () “buscar”.

No estoy seguro de por qué Visual Studio no me deja hacer esto fácilmente.

He intentado esto también, sin suerte:

 .Where(x => x.GetType().GetProperty(searchfield).GetValue(x, null).ToList().Contains(search)) 

Nota: no quiero instalar bibliotecas nuevas, esto debería ser increíblemente fácil y simple para un lenguaje moderno. No me importa si la consulta devuelve todas las filas y busco a través de ella DESPUÉS con .Contains ().

Esto no es trivial, pero creo que se puede hacer. Lo siguiente no ha sido probado. El código se toma prestado de aquí .

Crear un método de ayuda en algún lugar como

 public static Expression> GetContainsExpression(string propertyName, string containsValue) { var parameterExp = Expression.Parameter(typeof(T), "type"); var propertyExp = Expression.Property(parameterExp, propertyName); MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) }); var someValue = Expression.Constant(propertyValue, typeof(string)); var containsMethodExp = Expression.Call(propertyExp, method, someValue); return Expression.Lambda>(containsMethodExp, parameterExp); } public static Expression> GetPropertyExpression(string propertyName) { var parameterExp = Expression.Parameter(typeof(T), "type"); var exp = Expression.Property(parameterExp, propertyName); return Expression.Lambda>(exp, parameterExp); } 

Utilízalo como

 users = this.entities.tableUsers .Where(GetContainsExpression(searchfield, search)) .OrderBy(GetPropertyExpression(searchfield)) ... 

ACTUALIZAR

Como alternativa, puede crear métodos de extensión para proporcionar una syntax más limpia. Cree los siguientes métodos en una clase estática en algún lugar:

  public static IQueryable WhereStringContains(this IQueryable query, string propertyName, string contains) { var parameter = Expression.Parameter(typeof(T), "type"); var propertyExpression = Expression.Property(parameter, propertyName); MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) }); var someValue = Expression.Constant(contains, typeof(string)); var containsExpression = Expression.Call(propertyExpression, method, someValue); return query.Where(Expression.Lambda>(containsExpression, parameter)); } public static IOrderedQueryable OrderBy(this IQueryable query, string propertyName) { var propertyType = typeof(T).GetProperty(propertyName).PropertyType; var parameter = Expression.Parameter(typeof(T), "type"); var propertyExpression = Expression.Property(parameter, propertyName); var lambda = Expression.Lambda(propertyExpression, new[] { parameter }); return typeof(Queryable).GetMethods() .Where(m => m.Name == "OrderBy" && m.GetParameters().Length == 2) .Single() .MakeGenericMethod(new[] { typeof(T), propertyType }) .Invoke(null, new object[] { query, lambda }) as IOrderedQueryable; } public static IOrderedQueryable OrderByDescending(this IQueryable query, string propertyName) { var propertyType = typeof(T).GetProperty(propertyName).PropertyType; var parameter = Expression.Parameter(typeof(T), "type"); var propertyExpression = Expression.Property(parameter, propertyName); var lambda = Expression.Lambda(propertyExpression, new[] { parameter }); return typeof(Queryable).GetMethods() .Where(m => m.Name == "OrderByDescending" && m.GetParameters().Length == 2) .Single() .MakeGenericMethod(new[] { typeof(T), propertyType }) .Invoke(null, new object[] { query, lambda }) as IOrderedQueryable; } 

Entonces puedes llamarlos como:

 var users = this.entities.tableUsers.WhereStringContains(searchField, search) .OrderBy(searchField); 

Esto debería ser increíblemente fácil y simple para un lenguaje moderno.

No, no debería hacerlo si va en contra de ese paradigma del lenguaje. LINQ y Entity Framework (así como cualquier otro ORM decente) se hacen precisamente para evitar lo que se intenta lograr: consultas no tipificadas y no comstackbles. Así que básicamente estás forzando una clavija cuadrada en un agujero redondo.

Todavía puedes echar un vistazo a Dynamic LINQ .

Tendrás que construir un árbol de expresiones para pasar al método Where . Aquí hay una adaptación suelta de algunos códigos sobre los que estoy mintiendo:

 string searchfield, value; // Your inputs var param = Expression.Parameter(typeof(User), "user"); return Expression.Lambda>( Expression.Call( Expression.Property( param, typeof(User).GetProperty(searchfield)), typeof(string).GetMethod("Contains"), Expression.Constant(value)), param); 

Eso generará una expresión apropiada para usar como parámetro para Where .

EDIT: FYI, la expresión resultante se verá algo así como user => user.Foo.Contains(bar) .

EDITAR: Para ordenar, algo como esto (arrancado de mi clase DynamicOrderList):

 private IQueryable OrderQuery(IQueryable query, OrderParameter orderBy) { string orderMethodName = orderBy.Direction == SortDirection.Ascending ? "OrderBy" : "OrderByDescending"; Type t = typeof(T); var param = Expression.Parameter(t, "user"); var property = t.GetProperty(orderBy.Attribute); return query.Provider.CreateQuery( Expression.Call( typeof(Queryable), orderMethodName, new Type[] { t, typeof(string) }, query.Expression, Expression.Quote( Expression.Lambda( Expression.Property(param, property), param)) )); } 

Mi respuesta a tu otra pregunta sobre esto:

Al crear una ordenación dinámica de linq y buscar declaraciones de orden en Entity Framework