usar una recortar quitar longitud invertida extraer ejemplos como caracteres cadena c# linq entity-framework expression-trees

c# - una - generar orden de EF por expresión por cadena



string c# ejemplos (2)

Puede intentar convertir el método Generate en un método genérico:

private Expression<Func<Task, TResult>> Generate<TResult>(string orderby) { switch (orderby) { case "Time": return t => t.Time; case "Money": return t => t.RewardMoney; default: return t => t.Id; } }

Por lo tanto, si llama a este método, debe especificar el tipo de propiedad que desea ordenar de la siguiente manera:

_context.Items.OrderBy(Generate<decimal>("Money"));

Ahora recuerde que TResult solo puede ser un tipo primitivo o un tipo de enumeración.

Quiero generar expresión por parámetro de cadena, algún código como:

private Expression<Func<Task, T>> Generate(string orderby) { switch (orderby) { case "Time": return t => t.Time; case "Money": return t => t.RewardMoney; default: return t => t.Id; } }

entonces llámalo:

_context.Items.OrderBy(Generate("Money"));

¡Pero no puede compilar! Cambio T para objetar.

private Expression<Func<Task, object>> Generate(string orderby)

Entonces puede compilar, pero no funciona.

System.NotSupportedException: no se puede convertir el tipo ''System.Int32'' para escribir ''System.Object''. LINQ to Entities solo admite la conversión de primitiva EDM o tipos de enumeración.


Usando árboles de reflexión y expresión puede proporcionar los parámetros y luego llamar a la función OrderBy , en lugar de devolver Expression<Func<Task, T>> y luego llamar a OrderBy .

Tenga en cuenta que OrderBy es un método de extensión y se ha implementado en las clases System.Linq.Enumarable y System.Linq.Queryable . El primero es para linq-to-objects y el último es para linq-to-entities . entity-framework necesita el árbol de expresiones de la consulta para traducirlo a comandos SQL. Entonces usamos la implementación Queryable .

Se puede hacer por un método de extensión (explicaciones agregadas como comentarios):

public static IOrderedQueryable<TSource> OrderBy<TSource>( this IEnumerable<TSource> query, string propertyName) { var entityType = typeof(TSource); //Create x=>x.PropName var propertyInfo = entityType.GetProperty(propertyName); ParameterExpression arg = Expression.Parameter(entityType, "x"); MemberExpression property = Expression.Property(arg, propertyName); var selector = Expression.Lambda(property, new ParameterExpression[] { arg }); //Get System.Linq.Queryable.OrderBy() method. var enumarableType = typeof(System.Linq.Queryable); var method = enumarableType.GetMethods() .Where(m => m.Name == "OrderBy" && m.IsGenericMethodDefinition) .Where(m => { var parameters = m.GetParameters().ToList(); //Put more restriction here to ensure selecting the right overload return parameters.Count == 2;//overload that has 2 parameters }).Single(); //The linq''s OrderBy<TSource, TKey> has two generic types, which provided here MethodInfo genericMethod = method .MakeGenericMethod(entityType, propertyInfo.PropertyType); /*Call query.OrderBy(selector), with query and selector: x=> x.PropName Note that we pass the selector as Expression to the method and we don''t compile it. By doing so EF can extract "order by" columns and generate SQL for it.*/ var newQuery = (IOrderedQueryable<TSource>)genericMethod .Invoke(genericMethod, new object[] { query, selector }); return newQuery; }

Ahora puede llamar a esta sobrecarga de OrderBy como cualquier otra sobrecarga.
Por ejemplo:

var cheapestItems = _context.Items.OrderBy("Money").Take(10).ToList();

Que se traduce a:

SELECT TOP (10) {coulmn names} FROM [dbo].[Items] AS [Extent1] ORDER BY [Extent1].[Money] ASC

Este enfoque se puede usar para definir todas las sobrecargas de los métodos OrderBy y OrderByDescending para tener selector de propiedad de string .