Generate EF orderby expression by string

前端 未结 5 1509
不思量自难忘°
不思量自难忘° 2020-11-29 05:27

I want to generate expression by string parameter,some code like:

private Expression> Generate(string orderby)
{
    switch (orderb         


        
5条回答
  •  情书的邮戳
    2020-11-29 05:55

    Using reflection and expression-trees you can provide the parameters and then call OrderBy function, Instead of returning Expression> and then calling OrderBy.

    Note that OrderBy is an extension method and has implemented in both System.Linq.Enumarable and System.Linq.Queryable classes. The first one is for linq-to-objects and the latter is for linq-to-entities. entity-framework needs the expression tree of the query in order to translate it to SQL commands. So we use the Queryable implementation.

    It can be done by an extension method(explanations added as comments):

    public static IOrderedQueryable OrderBy(
           this IQueryable 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 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)genericMethod
             .Invoke(genericMethod, new object[] { query, selector });
        return newQuery;
    }
    

    Now you can call this overload of OrderBy like any other overload of it.
    For example:

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

    Which translates to:

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

    This approach can be used to define all overloads of OrderBy and OrderByDescending methods to have string property selector.

提交回复
热议问题