We are exposing XPO via OData 4 under WebApi 2.2 and already have some progress. Can you evaluate the problem with expanding a collection? On any single subentity it works good. It's happening at place showed in attached screenshot. On the left side it is XPCollection<CollectionItemType> and on the right is Boolean which causes wrong conversion.
http://localhost:91/WebApiOData/EntitySet(16)?$expand=CollectionProperty
{
"error":{
"code":"",
"message":"The query specified in the URI is not valid. No coercion operator is defined between types 'DevExpress.Xpo.XPCollection`1[CollectionItemType]' and 'System.Boolean'.",
"innererror":{
"message":"No coercion operator is defined between types 'DevExpress.Xpo.XPCollection`1[CollectionItemType]' and 'System.Boolean'.",
"type":"System.InvalidOperationException",
"stacktrace":"
at System.Linq.Expressions.Expression.GetUserDefinedCoercionOrThrow(ExpressionType coercionType, Expression expression, Type convertToType)
at System.Linq.Expressions.Expression.Convert(Expression expression, Type type, MethodInfo method)
at System.Linq.Expressions.Expression.Convert(Expression expression, Type type)
at DevExpress.Xpo.XPQueryBase.CreateSubItemCore(Type subType, ExpressionAccessOperator last, CriteriaTypeResolver resolver, ParameterExpression row, Int32& rowIndex)
at DevExpress.Xpo.XPQueryBase.CreateSubItemCore(Type subType, ExpressionAccessOperator last, CriteriaTypeResolver resolver, ParameterExpression row, Int32& rowIndex)
at DevExpress.Xpo.XPQueryBase.CreateSubItemCore(Type subType, ExpressionAccessOperator last, CriteriaTypeResolver resolver, ParameterExpression row, Int32& rowIndex)
at DevExpress.Xpo.XPQueryBase.CreateSubItemCore(Type subType, MemberInitOperator last, CriteriaTypeResolver resolver, ParameterExpression row, Int32& rowIndex)
at DevExpress.Xpo.XPQueryBase.CreateSubItemCore(Type subType, MemberInitOperator last, CriteriaTypeResolver resolver, ParameterExpression row, Int32& rowIndex)
at DevExpress.Xpo.XPQueryBase.CreateItemCore(Type type, MemberInitOperator last)
at DevExpress.Xpo.XPQueryBase.GetData(Type type)
at DevExpress.Xpo.XPQueryBase.Enumerate(Type type)
at DevExpress.Xpo.XPQuery`1.GetEnumerator()
at DevExpress.Xpo.XPQuery`1.System.Collections.IEnumerable.GetEnumerator()
at System.Web.OData.EnableQueryAttribute.SingleOrDefault(IQueryable queryable, HttpActionDescriptor actionDescriptor)
at System.Web.OData.EnableQueryAttribute.ExecuteQuery(Object response, HttpRequestMessage request, HttpActionDescriptor actionDescriptor)
at System.Web.OData.EnableQueryAttribute.OnActionExecuted(HttpActionExecutedContext actionExecutedContext)"
}
}
}
Hello Oleksandr.
I'm afraid the infromation you provided is insufficient to research the issue. It is unclear what you are doing and how. Would you please provide us with a small sample project demonstrating your sceanrio, describe your task in detail and explain how to replicate the issue?
It requires some time to do isolated example. I will try on next week.
Here example is. It uses Oracle and you will find SqlScripts.sql in root of the solution which creates tables and fulfill them. I guess you can use any DB because the problem looks DB independent. Connection string is located in WebApiConfig class. Example is built with VS 2013 Update 5. After running the service try next URLs:
http://localhost:52599/Products?$expand=Category
You should get:
HTTP/1.1 200 OK
{
"@odata.context":"http://localhost:52599/$metadata#Products";,
"value":
[
{
"Id":1,
"Name":"PROD1",
"Category":{"Id":1,"Name":"CAT1"}
},
{
"Id":2,
"Name":"PROD2",
"Category":{"Id":1,"Name":"CAT1"}
}
]
}
So expanding of single entity is working. Try to expand a collection
http://localhost:52599/Categories?$expand=Products
comes to
HTTP/1.1 500 Internal Server Error
{
"error":{
"code":"",
"message":"An error has occurred.",
"innererror":{
"message":"The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; odata.metadata=minimal; odata.streaming=true'.",
"type":"System.InvalidOperationException",
"stacktrace":"",
"internalexception":{
"message":"No coercion operator is defined between types 'DevExpress.Xpo.XPCollection`1[XpoOdataTest.Models.Product]' and 'System.Boolean'.",
"type":"System.InvalidOperationException",
"stacktrace":"
at System.Linq.Expressions.Expression.GetUserDefinedCoercionOrThrow(ExpressionType coercionType, Expression expression, Type convertToType)
at System.Linq.Expressions.Expression.Convert(Expression expression, Type type, MethodInfo method)
at System.Linq.Expressions.Expression.Convert(Expression expression, Type type)
at DevExpress.Xpo.XPQueryBase.CreateSubItemCore(Type subType, ExpressionAccessOperator last, CriteriaTypeResolver resolver, ParameterExpression row, Int32& rowIndex)
at DevExpress.Xpo.XPQueryBase.CreateSubItemCore(Type subType, ExpressionAccessOperator last, CriteriaTypeResolver resolver, ParameterExpression row, Int32& rowIndex)
at DevExpress.Xpo.XPQueryBase.CreateSubItemCore(Type subType, ExpressionAccessOperator last, CriteriaTypeResolver resolver, ParameterExpression row, Int32& rowIndex)
at DevExpress.Xpo.XPQueryBase.CreateSubItemCore(Type subType, MemberInitOperator last, CriteriaTypeResolver resolver, ParameterExpression row, Int32& rowIndex)
at DevExpress.Xpo.XPQueryBase.CreateSubItemCore(Type subType, MemberInitOperator last, CriteriaTypeResolver resolver, ParameterExpression row, Int32& rowIndex)
at DevExpress.Xpo.XPQueryBase.CreateItemCore(Type type, MemberInitOperator last)
at DevExpress.Xpo.XPQueryBase.GetData(Type type)
at DevExpress.Xpo.XPQueryBase.Enumerate(Type type)
at DevExpress.Xpo.XPQuery`1.GetEnumerator()
at DevExpress.Xpo.XPQuery`1.System.Collections.IEnumerable.GetEnumerator()
at System.Web.OData.Formatter.Serialization.ODataFeedSerializer.WriteFeed(IEnumerable enumerable, IEdmTypeReference feedType, ODataWriter writer, ODataSerializerContext writeContext)
at System.Web.OData.Formatter.Serialization.ODataFeedSerializer.WriteObjectInline(Object graph, IEdmTypeReference expectedType, ODataWriter writer, ODataSerializerContext writeContext)
at System.Web.OData.Formatter.Serialization.ODataFeedSerializer.WriteObject(Object graph, Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext)
at System.Web.OData.Formatter.ODataMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, HttpContent content, HttpContentHeaders contentHeaders)
at System.Web.OData.Formatter.ODataMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at System.Web.Http.WebHost.HttpControllerHandler.<WriteBufferedResponseContentAsync>d__1b.MoveNext()"
}
}
}
}
If you also can investigate why $select is not working on subentitties it would be highly appreciated:
http://localhost:52599/Categories(1)?$select=Products
HTTP/1.1 200 OK
{
"@odata.context":"http://localhost:52599/$metadata#Categories(Products)/$entity";
}
http://localhost:52599/Products(1)?$select=Category
HTTP/1.1 200 OK
{
"@odata.context":"http://localhost:52599/$metadata#Products(Category)/$entity";
}
It always returns empty result (selection of a primitive value works fine). If you grab everything it creates one empty entry for each parent record:
http://localhost:52599/Products?$select=Category
{
"@odata.context":"http://localhost:52599/$metadata#Products(Category)";,"value":[
{
},{
}
]
}
The same for collection:
http://localhost:52599/Categories?$select=Products
{
"@odata.context":"http://localhost:52599/$metadata#Categories(Products)";,"value":[
{
},{
}
]
}
Thanks!
Thank you for the sample. We need some time to research it. I will get back once we have any result.
We have researched this issue and come to the conclusion that it is a bug in our code. We will try to fix it as soon as we can. I'm afraid there's no simple workaround at the moment.
Ok, thanks! Do you know why $select doesn't work with an entity/collection?