C# 按字符串生成EF orderby表达式

C# 按字符串生成EF orderby表达式,c#,linq,entity-framework,expression-trees,reflection,linq-to-objects,linq-to-entities,C#,Linq,Entity Framework,Expression Trees,Reflection,Linq To Objects,Linq To Entities,我想通过字符串参数生成表达式,一些代码如下: private Expression<Func<Task, T>> Generate(string orderby) { switch (orderby) { case "Time": return t => t.Time; case "Money": return t => t.RewardMoney;

我想通过字符串参数生成表达式,一些代码如下:

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;
    }
}
但它不能编译!我把T改成object

private Expression<Func<Task, object>> Generate(string orderby)
private Expression Generate(字符串orderby)
然后它可以编译,但它不工作

System.NotSupportedException:无法将类型“System.Int32”强制转换为类型“System.Object”。LINQ to实体仅支持强制转换EDM基元或枚举类型


您可以尝试在通用方法中转换
Generate
方法:

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;
     }
}
private Expression Generate(字符串orderby)
{
交换机(订购方)
{
案例“时间”:
返回t=>t.时间;
“金钱”一案:
返回t=>t.报酬钱;
违约:
返回t=>t.Id;
}
}
因此,如果调用此方法,则需要指定要按其排序的属性的类型:

_context.Items.OrderBy(Generate<decimal>("Money"));
\u context.Items.OrderBy(生成(“货币”);
现在请记住,
TResult
只能是基元类型或枚举类型

使用并可以提供参数,然后调用
OrderBy
函数,而不是返回
Expression
然后调用
OrderBy

请注意,
OrderBy
是一种扩展方法,已在
System.Linq.enumable
System.Linq.Queryable
类中实现。第一个是给,第二个是给。需要查询的表达式树才能将其转换为SQL命令。因此,我们使用
Queryable
实现

可以通过扩展方法完成(解释添加为注释):

也就是说:

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

此方法可用于定义
OrderBy
OrderByDescending
方法的所有重载,使其具有
string
属性选择器。

使用通用方法。由于lambda表达式只能分配给强类型委托或表达式,因此我们必须使用相应的temp。然后我们可以将这个temp分配给一个类型为
object
的变量。最后,我们可以通过强制转换到结果类型来返回结果

public Expression<Func<Task, TResult>> Generate<TResult>(string orderby)
{
    object result;
    switch (orderby) {
        case "Time":
            Expression<Func<Task, DateTime>> temp1 = t => t.Time;
            result = temp1;
            break;
        case "Money":
            Expression<Func<Task, decimal>> temp2 = t => t.RewardMoney;
            result = temp2;
            break;
        default:
            Expression<Func<Task, int>> temp3 = t => t.Id;
            result = temp3;
            break;
    }
    return (Expression<Func<Task, TResult>>)result;
}
公共表达式生成(字符串orderby)
{
客观结果;
交换机(订购方){
案例“时间”:
表达式temp1=t=>t.时间;
结果=temp1;
打破
“金钱”一案:
表达式temp2=t=>t.RewardMoney;
结果=temp2;
打破
违约:
表达式temp3=t=>t.Id;
结果=temp3;
打破
}
返回(表达式)结果;
}
公共静态IQueryable OrderByHelper(此IQueryable源、字符串属性名称、字符串排序方向)
{
尝试
{
if(source==null)
{
返回源;
}
如果(propertyName==null)
{
返回源;
}
propertyName=propertyName.First().ToString().ToUpper(新的CultureInfo(“en-US”,false))+propertyName.Substring(1);
var类型=类型(T);
var arg=表达式参数(类型为“x”);
var propertyInfo=type.GetProperty(propertyName);
var mExpr=Expression.Property(arg,propertyInfo);
类型=propertyInfo.PropertyType;
var delegateType=typeof(Func)。MakeGenericType(typeof(T),type);
var lambda=Expression.lambda(delegateType,mExpr,arg);
var methodName=!string.IsNullOrEmpty(sortDirection)&&sortDirection.ToLower(new-CultureInfo(“en-US”,false))==“desc”?“OrderByDescending”:“OrderBy”;
var orderedSource=typeof(Queryable).GetMethods().Single(
method=>method.Name==methodName
&&方法.IsGenericMethodDefinition
&&方法。GetGenericArguments()。长度==2
&&方法。GetParameters().Length==2)
.MakeGenericMethod(typeof(T),type)
.Invoke(null,新对象[]{source,lambda});
返回(IQueryable)orderedSource;
}
捕获(例外)
{
返回源;
}
}
我在CodePlex中引用了旧版本,并从实现和调用的角度创建了一个非常简单的版本。当然,它是
IQueryable

/*
使用制度;
使用System.Linq;
使用System.Linq.Expressions;
*/
公共静态IQueryable OrderBy(此IQueryable查询,字符串orderByExpression)
{
if(string.IsNullOrEmpty(orderByExpression))
返回查询;
字符串propertyName,orderByMethod;
字符串[]strs=orderByExpression.Split(“”);
propertyName=strs[0];
如果(strs.Length==1)
orderByMethod=“OrderBy”;
其他的
orderByMethod=strs[1]。等于(“DESC”,StringComparison.OrderAlignOreCase)?“OrderByDescending”:“OrderBy”;
ParameterExpression pe=Expression.Parameter(query.ElementType);
MemberExpression me=Expression.Property(pe,propertyName);
MethodCallExpression orderByCall=Expression.Call(typeof(Queryable),orderByMethod,新类型[]{query.ElementType,me.Type},query.Expression
,Expression.Quote(Expression.Lambda(me,pe));
将query.Provider.CreateQuery(orderByCall)作为IQueryable返回;
}
下面是如何使用它的示例,针对Entity Framework Core 3进行了测试:

IQueryable<Person> query = dbContext.People;
query = query.OrderBy("FirstName"); // ORDER BY FirstName
IQueryable query=dbContext.People;
query=query.OrderBy(“FirstName”);//点名
IQueryable query=dbContext.People;
query=query.OrderBy(“FirstName ASC”);//点名
IQueryable query=dbContext.People;
query=query.OrderBy(“FirstName DESC”);//按名订购

谢谢您的回答,但当您将“时间”作为参数传递时,调用将更改:\u context.Items.OrderBy(Generate(“Time”))。这个函数失去了它的功能??可能是优秀扩展的复制品。
SELECT TOP (10)  {coulmn names} FROM  [dbo].[Items] AS [Extent1] 
       ORDER BY [Extent1].[Money] ASC
public Expression<Func<Task, TResult>> Generate<TResult>(string orderby)
{
    object result;
    switch (orderby) {
        case "Time":
            Expression<Func<Task, DateTime>> temp1 = t => t.Time;
            result = temp1;
            break;
        case "Money":
            Expression<Func<Task, decimal>> temp2 = t => t.RewardMoney;
            result = temp2;
            break;
        default:
            Expression<Func<Task, int>> temp3 = t => t.Id;
            result = temp3;
            break;
    }
    return (Expression<Func<Task, TResult>>)result;
}
public static IQueryable<T> OrderByHelper<T>(this IQueryable<T> source, string propertyName, string sortDirection)
    {

        try
        {
            if (source == null)
            {
                return source;
            }
            if (propertyName == null)
            {
                return source;
            }

            propertyName = propertyName.First().ToString().ToUpper(new CultureInfo("en-US", false)) + propertyName.Substring(1);
            var type = typeof(T);
            var arg = Expression.Parameter(type, "x");

            var propertyInfo = type.GetProperty(propertyName);
            var mExpr = Expression.Property(arg, propertyInfo);
            type = propertyInfo.PropertyType;

            var delegateType = typeof(Func<,>).MakeGenericType(typeof(T), type);
            var lambda = Expression.Lambda(delegateType, mExpr, arg);

            var methodName = !string.IsNullOrEmpty(sortDirection) && sortDirection.ToLower(new CultureInfo("en-US", false)) == "desc" ? "OrderByDescending" : "OrderBy";
            var orderedSource = typeof(Queryable).GetMethods().Single(
                method => method.Name == methodName
                        && method.IsGenericMethodDefinition
                        && method.GetGenericArguments().Length == 2
                        && method.GetParameters().Length == 2)
                .MakeGenericMethod(typeof(T), type)
                .Invoke(null, new object[] { source, lambda });

            return (IQueryable<T>)orderedSource;
        }
        catch (Exception)
        {

            return source;
        }
    }
/*
using System;
using System.Linq;
using System.Linq.Expressions;
*/

public static IQueryable<T> OrderBy<T>(this IQueryable<T> query, string orderByExpression)
{
    if (string.IsNullOrEmpty(orderByExpression))
        return query;

    string propertyName, orderByMethod;
    string[] strs = orderByExpression.Split(' ');
    propertyName = strs[0];

    if (strs.Length == 1)
        orderByMethod = "OrderBy";
    else
        orderByMethod = strs[1].Equals("DESC", StringComparison.OrdinalIgnoreCase) ? "OrderByDescending" : "OrderBy";

    ParameterExpression pe = Expression.Parameter(query.ElementType);
    MemberExpression me = Expression.Property(pe, propertyName);

    MethodCallExpression orderByCall = Expression.Call(typeof(Queryable), orderByMethod, new Type[] { query.ElementType, me.Type }, query.Expression
        , Expression.Quote(Expression.Lambda(me, pe)));

    return query.Provider.CreateQuery(orderByCall) as IQueryable<T>;
}
IQueryable<Person> query = dbContext.People;
query = query.OrderBy("FirstName"); // ORDER BY FirstName
IQueryable<Person> query = dbContext.People;
query = query.OrderBy("FirstName ASC"); // ORDER BY FirstName
IQueryable<Person> query = dbContext.People;
query = query.OrderBy("FirstName DESC"); // ORDER BY FirstName DESC