Я пытаюсь изменить дерево выражений запроса OData, прежде чем он достигнет базы данных.Так как мой ExpressionVisitor относится к запросу, я не могу использовать метод ParseQuery в QueryModelGenerator, чтобы изменить его.Поскольку я заранее не знаю тип дерева выражений (это может быть SelectExpandBinder SelectSome, SelectExpandBinder SelectAllAndExpand, ...), я должен использовать отражение для вызова метода CreateQuery.Я не уверен, что это правильный подход.
[EnableQuery(MaxExpansionDepth = 0)]
public new ActionResult<Product> Get(ODataQueryOptions<Product> odataQueryOptions)
{
var get = this.dbContext.Products;
var getWithOdataQueryOptions = odataQueryOptions.ApplyTo(get);
var expression = this.productVisitor.Visit(getWithOdataQueryOptions.Expression);
// Not sure if this is the right way.
var method = typeof(IQueryProvider).GetMethods().Where(w => w.Name == "CreateQuery" && w.IsGenericMethod).First();
var generic = method.MakeGenericMethod(expression.Type.GenericTypeArguments[0]);
var result = generic.Invoke(getWithOdataQueryOptions.Provider, new[] { expression });
return this.Ok(result);
}
Этот подход отлично подходит для запросов OData без $ expand или $ select.Но как только я запрашиваю что-то вроде / Products? $ Select = Id, я получаю следующее исключение:
{
"error": {
"code": "",
"message": "The query specified in the URI is not valid. Could not find a property named 'Id' on type 'Microsoft.AspNet.OData.Query.Expressions.SelectSome_1OfProduct'.",
"details": [],
"innererror": {
"message": "Could not find a property named 'id' on type 'Microsoft.AspNet.OData.Query.Expressions.SelectSome_1OfProduct'.",
"type": "Microsoft.OData.ODataException",
"stacktrace": " at Microsoft.OData.UriParser.SelectPathSegmentTokenBinder.ConvertNonTypeTokenToSegment(PathSegmentToken tokenIn, IEdmModel model, IEdmStructuredType edmType, ODataUriResolver resolver)\r\n at Microsoft.OData.UriParser.SelectPropertyVisitor.ProcessTokenAsPath(NonSystemToken tokenIn)\r\n at Microsoft.OData.UriParser.SelectPropertyVisitor.Visit(NonSystemToken tokenIn)\r\n at Microsoft.OData.UriParser.SelectBinder.Bind(SelectToken tokenIn)\r\n at Microsoft.OData.UriParser.SelectExpandBinder.Bind(ExpandToken tokenIn)\r\n at Microsoft.OData.UriParser.SelectExpandSemanticBinder.Bind(ODataPathInfo odataPathInfo, ExpandToken expandToken, SelectToken selectToken, ODataUriParserConfiguration configuration)\r\n at Microsoft.OData.UriParser.ODataQueryOptionParser.ParseSelectAndExpandImplementation(String select, String expand, ODataUriParserConfiguration configuration, ODataPathInfo odataPathInfo)\r\n at Microsoft.OData.UriParser.ODataQueryOptionParser.ParseSelectAndExpand()\r\n at Microsoft.AspNet.OData.Query.Validators.SelectExpandQueryValidator.Validate(SelectExpandQueryOption selectExpandQueryOption, ODataValidationSettings validationSettings)\r\n at Microsoft.AspNet.OData.Query.Validators.ODataQueryValidator.Validate(ODataQueryOptions options, ODataValidationSettings validationSettings)\r\n at Microsoft.AspNet.OData.EnableQueryAttribute.ValidateQuery(HttpRequest request, ODataQueryOptions queryOptions)\r\n at Microsoft.AspNet.OData.EnableQueryAttribute.<>c__DisplayClass1_0.<OnActionExecuted>b__1(ODataQueryContext queryContext)\r\n at Microsoft.AspNet.OData.EnableQueryAttribute.ExecuteQuery(Object responseValue, IQueryable singleResultCollection, IWebApiActionDescriptor actionDescriptor, Func`2 modelFunction, IWebApiRequestMessage request, Func`2 createQueryOptionFunction)\r\n at Microsoft.AspNet.OData.EnableQueryAttribute.OnActionExecuted(Object responseValue, IQueryable singleResultCollection, IWebApiActionDescriptor actionDescriptor, IWebApiRequestMessage request, Func`2 modelFunction, Func`2 createQueryOptionFunction, Action`1 createResponseAction, Action`3 createErrorAction)"
}
}
}
Как вы можете видеть из приведенного ниже кода, я фактически пытался полностью и просто удалить своего посетителя.создать новый IQueryable на основе дерева выражений, не меняя его, и я получаю тот же результат.
var get = this.dbContext.Products;
var getWithOdataQueryOptions = odataQueryOptions.ApplyTo(get);
// Not sure if this is the right way.
var method = typeof(IQueryProvider).GetMethods().Where(w => w.Name == "CreateQuery" && w.IsGenericMethod).First();
var generic = method.MakeGenericMethod(getWithOdataQueryOptions.Expression.Type.GenericTypeArguments[0]);
var result = generic.Invoke(getWithOdataQueryOptions.Provider, new[] { getWithOdataQueryOptions.Expression });
return this.Ok(result);
Как я могу изменить дерево выражений для определенного контекста (то есть без использования QueryModelGenerator) без потери ODataфункциональность?