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
1[NoSqlModels.PhoneBookCategory] 搜索[PhoneBookCategory](System.Linq.IQueryable`1[NoSqlModels.PhoneBookCategory], 系统.字符串,系统.字符串,系统.十进制, Raven.Client.Documents.SearchOptions, Raven.Client.Documents.Queries.SearchOperator)'(参数 '参数1')'2[NoSqlModels.PhoneBookCategory,System.String]' cannot be used for parameter of type 'System.String' of method 'Raven.Client.Documents.Linq.IRavenQueryable
所以看来我的
exprGetter
返回的是Expression这里有一个解决方案,它消除了原始方法的大部分复杂性:
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);
}
它只是生成字段选择器,然后调用原始扩展方法。