MethodCallExpression orderby

Laz*_*az5 5 c# linq entity-framework

我正在尝试使用表达式树构建 lambda 查询,以使其在整个应用程序中通用。我的初步尝试基于此处找到的代码。我更改了代码,以便它执行比较以返回姓氏刚好在 searchText 之前的 100 个实体,如下所示:

TEntity entity = entitySet.FirstOrDefault();
string searchName = entity.GetType().GetProperty("SearchName").ToString();
searchText = "Baker";
int records = 100;

IQueryable<TEntity> queryableData = entitySet.AsQueryable<TEntity>();
var param = Expression.Parameter(typeof(TEntity), searchName);
var body = Expression.LessThan(Expression.Call(
    typeof(string), 
    "Compare", 
    null, 
    Expression.PropertyOrField(param, searchName), 
    Expression.Constant(searchText)), 
    Expression.Constant(0));

var lambda = Expression.Lambda<Func<TEntity, bool>>(body, param);

MethodCallExpression whereCallExpression = Expression.Call(
    typeof(Queryable),
    "Where",
    new Type[] { typeof(TEntity) },
    queryableData.Expression,
    lambda);

var data = entitySet.AsQueryable<TEntity>().Provider.CreateQuery<TEntity>(whereCallExpression).Take(records);
Run Code Online (Sandbox Code Playgroud)

上面的代码有效,它从数据库中返回 100 个位于我的 searchText 之前的实体,但它们是错误的实体,因为它们在 entitySet 中没有按顺序排列。因此,我的表达式树中需要一个 OrderBy 子句,以便获得“Azure”、Axel、Avis 等。

我试过这个:

 MethodCallExpression orderByCallExpression = Expression.Call(
    typeof(Queryable),
    "OrderByDescending",
    new Type[] { typeof(TEntity), typeof(TEntity) },
    whereCallExpression,
    Expression.Lambda<Func<TEntity, string>>(param, new ParameterExpression[] { param }));

var data = entitySet.AsQueryable<TEntity>().Provider.CreateQuery<TEntity>(orderByCallExpression).Take(records);
Run Code Online (Sandbox Code Playgroud)

我收到错误“System.Core.dll 中发生类型为‘System.ArgumentException’的异常,但未在用户代码中处理

附加信息:类型 MyEntity' 的表达式不能用于返回类型 'System.String'"

堆栈跟踪:

在 System.Linq.Expressions.Expression.ValidateLambdaArgs(Type delegateType, Expression& body, ReadOnlyCollection`1 个参数)

在 System.Linq.Expressions.Expression.Lambda[TDelegate](Expression body, String name, Boolean tailCall, IEnumerable`1 个参数)

在 System.Linq.Expressions.Expression.Lambda[TDelegate](Expression body, Boolean tailCall, IEnumerable`1 个参数)

所以,我看这里并尝试了这个:

Expression<Func<TEntity, string>> sortExp = l => l.SearchName);

MethodCallExpression orderByCallExpression = Expression.Call(
    typeof(Queryable),
    "OrderByDescending",
    new Type[] { typeof(TEntity), typeof(string) },
    whereCallExpression,
    sortExp);
Run Code Online (Sandbox Code Playgroud)

我收到错误消息“mscorlib.dll 中发生了类型为‘System.NotSupportedException’的异常,但未在用户代码中处理

附加信息:LINQ to Entities 不支持指定的类型成员“SearchName”。仅支持初始值设定项、实体成员和实体导航属性。”

我认为问题在于 SearchName 属性是一个字符串,其中包含我想要 OrderBy 的实体上的字段名称。我试过:

l => (string)l.GetType().GetProperty("SearchName").GetValue(SearchName);
Run Code Online (Sandbox Code Playgroud)

但这给了我错误:“mscorlib.dll 中发生了类型为‘System.NotSupportedException’的异常,但未在用户代码中处理

附加信息:LINQ to Entities 无法识别“System.Object GetValue(System.Object)”方法,并且此方法无法转换为存储表达式。”

TEntity基于 EntityObject

SearchName是 TEntity 上字符串类型的属性,它保存数据库中的字段名称。

entitySet是类型ObjectSet<TEntity>

任何建议,将不胜感激。

更新和解决方案 我在这里找到了让我思考不同方向的代码。这是用于按 SearchName 排序的代码:

var type = typeof(TEntity);
var property = type.GetProperty(searchName);
var parameter = Expression.Parameter(type, "p");
var propertyAccess = Expression.MakeMemberAccess(parameter, property);
var orderByExp = Expression.Lambda(propertyAccess, parameter);

MethodCallExpression orderByCallExpression = Expression.Call(
        typeof(Queryable),
        "OrderByDescending",
        new Type[] { typeof(TEntity), typeof(string) },
        whereCallExpression,
        Expression.Quote(orderByExp));                                   

var data = entitySet.AsQueryable<TEntity>().Provider.CreateQuery<TEntity>(orderByCallExpression).Take(records);
Run Code Online (Sandbox Code Playgroud)

Laz*_*az5 0

这是我用于搜索名称不是表中的字段的解决方案。

if (entity.SearchName == "LastFirstName")
{
    //// Construct Expressions to hold the propert values
    Expression lastNameExp = Expression.PropertyOrField(param, "LastName");
    Expression firstNameExp = Expression.PropertyOrField(param, "FirstName");

    //// Construct a String.Concat method. 
    MethodInfo methodInfo = typeof(string).GetMethod("Concat", new Type[] { typeof(string), typeof(string) });

    //// Combine the LastName + FirstName for the compare
    MethodCallExpression combinedExp = Expression.Call(methodInfo, lastNameExp, firstNameExp);
Run Code Online (Sandbox Code Playgroud)