为 RavenDb 构建通用搜索 - 无法创建表达式<Func<T,object>>

问题描述 投票:0回答:1

IRavenQueryable 上的标准搜索方法如下所示:

public static IRavenQueryable<T> Search<T>(this IQueryable<T> self, Expression<Func<T, object>> fieldSelector, string searchTerms, decimal boost = 1m, SearchOptions options = SearchOptions.Guess, SearchOperator @operator = SearchOperator.Or)
{
    MethodInfo method = (MethodInfo)MethodBase.GetCurrentMethod();
    return (IRavenQueryable<T>)self.Provider.CreateQuery(Expression.Call(null, method, self.Expression, fieldSelector, Expression.Constant(searchTerms), Expression.Constant(boost), Expression.Constant(options), Expression.Constant(@operator)));
}

该方法的完整源代码可以在这里找到

我想创建另一个扩展方法,该方法允许我指定要使用其名称搜索的属性。所以我想出了这个

public static IRavenQueryable<T> Search<T>(this IQueryable<T> self, string fieldName, string searchTerms, decimal boost = 1m, SearchOptions options = SearchOptions.Guess, SearchOperator @operator = SearchOperator.Or)
{
    MethodInfo method = (MethodInfo)MethodBase.GetCurrentMethod();
    var info = typeof(T).GetProperty(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
        ?? throw new Exception($"{fieldName} is not a valid property on {typeof(T).Name}");
    var parTarget = Expression.Parameter(info.DeclaringType, "target");
    var exprGetter = Expression.Lambda(typeof(Func<,>).MakeGenericType(info.DeclaringType, typeof(object)), Expression.Property(parTarget, info), parTarget);
    return (IRavenQueryable<T>)self.Provider.CreateQuery(Expression.Call(null, method, self.Expression, exprGetter, Expression.Constant(searchTerms), Expression.Constant(boost), Expression.Constant(options), Expression.Constant(@operator)));
}

如果我调用它,我会得到一个 ArgumentException (我正在进行的搜索是在 NoSqlModels.PhoneBookCategory 上进行的,并且

fieldName
中使用的属性是字符串类型)

System.ArgumentException:'类型的表达式 'System.Func

2[NoSqlModels.PhoneBookCategory,System.String]' cannot be used for parameter of type 'System.String' of method  'Raven.Client.Documents.Linq.IRavenQueryable
1[NoSqlModels.PhoneBookCategory] 搜索[PhoneBookCategory](System.Linq.IQueryable`1[NoSqlModels.PhoneBookCategory], 系统.字符串,系统.字符串,系统.十进制, Raven.Client.Documents.SearchOptions, Raven.Client.Documents.Queries.SearchOperator)'(参数 '参数1')'

所以看来我的

exprGetter
返回的是Expression,而不是所需的Expression。那么我需要改变什么才能让它发挥作用

c# lambda expression ravendb
1个回答
0
投票

这里有一个解决方案,它消除了原始方法的大部分复杂性:

public static IRavenQueryable<T> Search<T>(this IQueryable<T> self, string fieldName, string searchTerms, decimal boost = 1m, SearchOptions options = SearchOptions.Guess, SearchOperator @operator = SearchOperator.Or)
{
    var parameter = Expression.Parameter(typeof(T));
    var property = Expression.Property(parameter, propName);
    expGetter = Expression.Lambda<Func<T, P>>(property, parameter);
    return self.Search(expGetter, searchTerms, boost, options, @operator);
}

它只是生成字段选择器,然后调用原始扩展方法。

© www.soinside.com 2019 - 2024. All rights reserved.