我目前在教導自己OData,但我遇到了一直無法解決的情況。要麼是我誤解OData規範,要麼我需要做一些事情才能使其發揮作用。OData over Web API - 如何查詢嵌套屬性?
我建立了書籍和作者實體(EF/CF)的小型模型。很簡單的東西從作者到書一到一對多的關係:
modelBuilder.Entity<Book>().HasRequired(b => b.Author);
modelBuilder.Entity<Author>().HasMany(a => a.Books);
現在,查詢作者,當我想能夠擴大其(嵌套)性質的書籍屬性和過濾器。例如,如果我問:「是誰寫的哈利波特」,像這樣......
http://myBooksDatabase/Authors?$expand=Books&$filter=contains(Books/Name,'Harry Potter')&$select=Name
...我得到這個錯誤響應:
{
error: {
code: ""
message: "The query specified in the URI is not valid. The parent value for a property access of a property 'Name' is not a single value. Property access can only be applied to a single value."
innererror: {
message: "The parent value for a property access of a property 'Name' is not a single value. Property access can only be applied to a single value."
type: "Microsoft.OData.Core.ODataException"
stacktrace: " at Microsoft.OData.Core.UriParser.Parsers.EndPathBinder.BindEndPath(EndPathToken endPathToken) at Microsoft.OData.Core.UriParser.Parsers.MetadataBinder.BindEndPath(EndPathToken endPathToken) at Microsoft.OData.Core.UriParser.Parsers.MetadataBinder.Bind(QueryToken token) at Microsoft.OData.Core.UriParser.Parsers.MetadataBinder.BindFunctionParameter(FunctionParameterToken token) at Microsoft.OData.Core.UriParser.Parsers.MetadataBinder.Bind(QueryToken token) at Microsoft.OData.Core.UriParser.Parsers.FunctionCallBinder.<BindFunctionCall>b__8(FunctionParameterToken ar) at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext() at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection) at Microsoft.OData.Core.UriParser.Parsers.FunctionCallBinder.BindFunctionCall(FunctionCallToken functionCallToken) at Microsoft.OData.Core.UriParser.Parsers.MetadataBinder.BindFunctionCall(FunctionCallToken functionCallToken) at Microsoft.OData.Core.UriParser.Parsers.MetadataBinder.Bind(QueryToken token) at Microsoft.OData.Core.UriParser.Parsers.FilterBinder.BindFilter(QueryToken filter) at Microsoft.OData.Core.UriParser.ODataQueryOptionParser.ParseFilterImplementation(String filter, ODataUriParserConfiguration configuration, IEdmType elementType, IEdmNavigationSource navigationSource) at Microsoft.OData.Core.UriParser.ODataQueryOptionParser.ParseFilter() at System.Web.OData.Query.FilterQueryOption.get_FilterClause() at System.Web.OData.Query.Validators.FilterQueryValidator.Validate(FilterQueryOption filterQueryOption, ODataValidationSettings settings) at System.Web.OData.Query.FilterQueryOption.Validate(ODataValidationSettings validationSettings) at System.Web.OData.Query.Validators.ODataQueryValidator.Validate(ODataQueryOptions options, ODataValidationSettings validationSettings) at System.Web.OData.Query.ODataQueryOptions.Validate(ODataValidationSettings validationSettings) at System.Web.OData.EnableQueryAttribute.ValidateQuery(HttpRequestMessage request, ODataQueryOptions queryOptions) at System.Web.OData.EnableQueryAttribute.ExecuteQuery(Object response, HttpRequestMessage request, HttpActionDescriptor actionDescriptor) at System.Web.OData.EnableQueryAttribute.OnActionExecuted(HttpActionExecutedContext actionExecutedContext)"
}-
}-
}
我知道我可以從查詢圖書實體...
http://myBooksDatabase/Books?$expand=Author&$filter=contains(Name,'Harry')
...但我得到的問題來自於當我嘗試引用嵌套的屬性時,不管我怎麼做。上面的查詢工作,並提出了整體作者實體,但如果我添加&$select=Author/Name
我得到如下回應:
{
error: {
code: ""
message: "The query specified in the URI is not valid. Found a path with multiple navigation properties or a bad complex property path in a select clause. Please reword your query such that each level of select or expand only contains either TypeSegments or Properties."
innererror: {
message: "Found a path with multiple navigation properties or a bad complex property path in a select clause. Please reword your query such that each level of select or expand only contains either TypeSegments or Properties."
type: "Microsoft.OData.Core.ODataException"
stacktrace: " at Microsoft.OData.Core.UriParser.Visitors.SelectPropertyVisitor.ProcessTokenAsPath(NonSystemToken tokenIn) at Microsoft.OData.Core.UriParser.Visitors.SelectPropertyVisitor.Visit(NonSystemToken tokenIn) at Microsoft.OData.Core.UriParser.Syntactic.NonSystemToken.Accept(IPathSegmentTokenVisitor visitor) at Microsoft.OData.Core.UriParser.Parsers.SelectBinder.Bind(SelectToken tokenIn) at Microsoft.OData.Core.UriParser.Parsers.SelectExpandBinder.Bind(ExpandToken tokenIn) at Microsoft.OData.Core.UriParser.Parsers.SelectExpandSemanticBinder.Bind(IEdmStructuredType elementType, IEdmNavigationSource navigationSource, ExpandToken expandToken, SelectToken selectToken, ODataUriParserConfiguration configuration) at Microsoft.OData.Core.UriParser.ODataQueryOptionParser.ParseSelectAndExpandImplementation(String select, String expand, ODataUriParserConfiguration configuration, IEdmStructuredType elementType, IEdmNavigationSource navigationSource) at Microsoft.OData.Core.UriParser.ODataQueryOptionParser.ParseSelectAndExpand() at System.Web.OData.Query.Validators.SelectExpandQueryValidator.Validate(SelectExpandQueryOption selectExpandQueryOption, ODataValidationSettings validationSettings) at System.Web.OData.Query.SelectExpandQueryOption.Validate(ODataValidationSettings validationSettings) at System.Web.OData.Query.Validators.ODataQueryValidator.Validate(ODataQueryOptions options, ODataValidationSettings validationSettings) at System.Web.OData.Query.ODataQueryOptions.Validate(ODataValidationSettings validationSettings) at System.Web.OData.EnableQueryAttribute.ValidateQuery(HttpRequestMessage request, ODataQueryOptions queryOptions) at System.Web.OData.EnableQueryAttribute.ExecuteQuery(Object response, HttpRequestMessage request, HttpActionDescriptor actionDescriptor) at System.Web.OData.EnableQueryAttribute.OnActionExecuted(HttpActionExecutedContext actionExecutedContext)"
}-
}-
}
這裏是我的兩個的OData控制器爲作者和書籍:
namespace My.OData.Controllers
{
public class AuthorsController : ODataController
{
// GET /Author
[EnableQuery]
public IQueryable<Author> Get()
{
return MediaContext.Singleton.Authors;
}
// GET /Authors(<key>)
[EnableQuery]
public SingleResult<Author> Get([FromODataUri] Guid key)
{
var result = MediaContext.Singleton.Authors.Where(b => b.Id == key);
return SingleResult.Create(result);
}
// GET /Authors(<key>)/Books
[EnableQuery]
public IQueryable<Book> GetBooks([FromODataUri] Guid key)
{
return MediaContext.Singleton.Authors.Where(a => a.Id == key).SelectMany(author => author.Books);
}
}
public class BooksController : ODataController
{
// GET /Books
[EnableQuery]
public IQueryable<Book> Get()
{
return MediaContext.Singleton.Books;
}
// GET /Books(<key>)
[EnableQuery]
public SingleResult<Book> Get([FromODataUri] Guid key)
{
var result = MediaContext.Singleton.Books.Where(b => b.Id == key);
return SingleResult.Create(result);
}
// GET /Books(<key>)/Author
[EnableQuery]
public SingleResult<Author> GetAuthor([FromODataUri] Guid key)
{
return SingleResult.Create(MediaContext.Singleton.Books.Where(b => b.Id == key).Select(b => b.Author));
}
}
}
因此,像我說過,還有什麼我需要添加或配置,使相關實體中的引用屬性工作?
好了,多了一些調查和V4的OData規範的閱讀教給我的過濾器語法應該是使用「any」函數,如下所示: http:// myBooksDatabase/Authors?$ filter = Books/any(b:contains(b/Name,'Harry Potter'))。這是有效的,但是如果我需要一些*屬性的書籍,比如標題和ISBN呢?我仍然無法弄清楚如何指定一個$ select語句來將嵌套屬性限制爲我需要的。 –