Change the Reference in a Single-Valued Navigation Property via OData v4 Model in SAPUI5 - odata

How am I supposed to change a reference in a single-valued navigation property using the UI5 OData v4 Model?
The OData documentation states that this could be accomplished by following request:
PUT serviceRoot/People('russellwhyte')/Trips(1001)/PlanItems(11)/Microsoft.OData.SampleService.Models.TripPin.Flight/Airline/$ref
OData-Version: 4.0
Content-Type: application/json;odata.metadata=minimal
Accept: application/json
{
"#odata.id": "serviceRoot/Airlines('FM')"
}
But I cannot find a way to achieve this by using the UI5 classes in sap.ui.model.odata.v4.
Am I missing something? If I try to change the value of the navigation property via the setProperty method of sap.ui.model.odata.v4.Context I get an error that states that $ref is not a (navigation) property. Besides that the setProperty method only allows primitive values.
Any kind of help is much appreciated.
Greetings
Marvin

Related

Change swagger mock default response

I'm currently using Swagger node.js and I am able to get a response through swagger with the mock option enabled (swagger project start -m)
However, when I hit the API, the mock response is very primitive.
"description": "Sample text",
"disabled": true,
So for string properties, I get back "Sample Text" and for Boolean, I get back True.
Is there any way to control these values? Maybe force swagger to refer to the example property?
I looked online, but couldn't find any way to achieve this.
swagger-node-express does not use the example values specified in the API definition. To customize mock responses, you'll need to create custom mock controllers.
From the documentation:
By default, mock mode returns programmed responses, like "Sample text" for a string, a number for an integer, and so on.
But you can also create mock controllers with handler methods that return custom responses.
Place these custom "mock" controllers in the /api/mock directory.
But there are other OpenAPI/Swagger mock servers that support example values.

PATCH collection with ODATA

Using the ODATA standard is it possible to patch an entity property collection by sending just the new item? And what is the result returned?
It could be something like
PATCH Persons/1/Addresses
{"city": "SF", "country": "US"}
What should it return? A Person or Address?
According to odata v4 protocol, collection property is treated as a unity, and does not support partially update.
See Update a Collection Property
A successful PUT request to the edit URL of a collection property
updates that collection. The message body MUST contain the desired new
value, formatted as a collection property according to the specified
format. The service MUST replace the entire value with the value
supplied in the request body. Since collection members have no
individual identity, PATCH is not supported for collection properties.
You can need to use PUT request in this case, both request and response payloads should be the whole collection.

Passing parameters to an OData (GET) method which returns a collection

I am using OData v3. How do I pass a parameter to an OData controller and return a collection? Example of what I am trying to do:
[EnableQuery(AllowedQueryOptions = AllowedQueryOptions.All)]
public IQueryable<ServiceInfoResult> Get([FromODataUri] int instanceId)
{
//etc
}
When I test this, I get this error:
No HTTP resource was found that matches the request URI 'http://localhost:30863/odata/ServiceInfoResultApi(1)'.
No action was found on the controller 'ServiceInfoResultApi' that matches the request.
I am aware of OData actions, but they are not a viable option on this case, because I need to get odata.count returned in the response, but no matter what I do, I cannot get that property returned when using OData actions (even when trying what was suggested here: Web API OData Inlinecount not working and here: Webapi odata expand with entity framework functions). So it would seem my only alternative was to create a new OData API controller for the ServiceInfoResult entity, so that I can avoid OData actions. However, as you can see above, passing in a parameter to a method that returns a collection seems to cause other errors.
Any solutions? And no, I can't update to OData v4, since that presents a whole host of other issues (it would take more time than I have and moreover, it doesn't support DateTime)
UPDATE
Thanks to #Fan Ouyang, I've discovered the reason for odata.count missing in the JSON payload is that I am not returning an entity type. If ServiceInfoResult were an entity in my database, odata.count would be returned. A bit silly that it's not being returned just because of that, but that's just how it is. I'm wondering if there's any workaround. For example, can I download the source code, change 1 line of code and use that? Otherwise, maybe it's time I started looking at OData v4. The project I have is quite big, so that's not a nice thought with the short amount of time I have. So, if there's any alternatives, I'd like to hear them. Thanks!
Try this sample, CheckoutMany method take parameter and return a collection https://github.com/OData/ODataSamples/tree/master/WebApi/v3/ODataActionsSample
Add [EnableQuery] attribute in the CheckOutMany action method, and add $inlinecount queryoption in requset url, you can see odata.count in payload
By the way, V4 support datetime now: http://odata.github.io/WebApi/#04-01-datetime-support
This was recently fixed with the release of version 5.7 (#odata.count is now returned for collections of complex types). More info here:
https://github.com/OData/WebApi/issues/484#issuecomment-153929767

OData Null Navigation Property while using Typeless Entity Object Support in Web API

I have two types Person and Honorific with a 0..1 to Many relationship between them. I am using queryOptions.request.SetSelectExpandClass to support expand and it works perfectly to expand Honorific when there is an Honorific.
When there is no Honorific I need the Json payload to include Honorific=(null). In that situation I return a null from TryGetPropertyValue but the Json serializer completely omits any reference to Honorific where it should insert Honorif=(null). Any ideas on how to achieve this? Thanks!
I don't think OData allows that the value of a collection is null.
A null collection is handled by WebAPI which will ignore a null collection during serialization.
I think it is a bug in WebAPI and a null collection should be treated as an empty collection during serialization.
Check the source code of WebAPI blow:
For OData V3:
\src\System.Web.Http.OData\OData\Formatter\Serialization\ODataEntityTypeSerializer.cs:WriteExpandedNavigationProperty
For OData V4:
\src\System.Web.OData\OData\Formatter\Serialization\ODataEntityTypeSerializer.cs:WriteExpandedNavigationProperty

Using navigation properties in entity framework code first

Context:
Code First, Entity Framework 4.3.1;
User ---- Topic, 1 to Many relation;
User with public virtual ICollection<Topic> CreatedTopics Navigation Property(Lazy Loading);
Topic with public virtual User Creator Navigation Property;
DataServiceController : DbDataController<DefaultDbContext>, Web API beta, ASP.NET MVC 4 Beta , Single Page Application;
System.Json for Json serialization;
Web API Action:
public IQueryable<Topic> GetTopics()
{
// return DbContext.Topics; // OK
return DbContext.Topics.Include("Creator"); //With Exception
}
Result: "an unhandled microsoft .net framework exception occurred in w3wp.exe"
The Problem here seems to be: I should not Add Navigation Property in both Entities(Cause Circular Reference?), and if I delete the CreatedTopics Navigation Property in User Class, It will be OK again.
So, In a similar Context like listed above, Here are my questions:
How to deal with Navigation Properties in the situation of 1 to Many relation;
Further more, how about a Many to Many relation, do i have to divide it into two 1 to Many relations;
What is the Best Practices and Precautions of using Navigation Properties?
I Have read many related posts, but still not clear enough :(,
Thanks for any help!
Dean
This is not a problem of code first or EF - it is a problem of serialization. Simply the serializer used to convert your object graph to some representation passed in a Web API message is not able to work with circular references by default. Depending on the message format you want to use Web API uses different serializers by default - here is more about default serializers used by Web API and about the way how to change it. The following text suppose that you are using DataContractJsonSerializer or DataContractSerializer (should be default for XML serialization) but the same is possible for JSON.NET (should be default for JSON serialization - JSON serialization can be switched to DataContractJsonSerializer but the default serializer is better).
So what you can do? You can tell the serializer that it should track those circular references by marking your classes with DataContract(IsReference = true) and each passed property with DataMember attribute (check the linked article for description how to achieve it with JSON.NET). This will allow serializer correctly recognizing cycles and the serialization will in theory succeed. In theory because this also demands to not using lazy loading. Otherwise you can serialize much more data than you expected (in some catastrophic scenarios it can lead to serializing whole content of your database).
When you serialize entity graph with lazy loading enabled you serailze a Topic and its Creator but serialization will also visit CreatedTopics property => all related topics are lazy loaded and processed by serialization and serialization continues to visit Creator of all newly loaded topics! This process continues until there is no other object to lazy load. Because of this you should never use lazy loading when serializing entities.
Other option is to exclude back reference from serialization. You just need to serialize Creator. You don't need to serialize CreatedTopics so you can mark the property with IgnoreDataMember attribute (JsonIgnore for JSON.NET). The problem is that if you also have Web API action for returning User with all his CreateTopics this will not work because of the attribute.
The last option is not using entities. This option is usually used in web services where you create special DTO objects satisfying requirements for specific operation and you handle conversion between entities and DTOs inside the operation (possible with help of some tool like AutoMapper).
There is no difference between handling one-to-one, one-to-many, or many-to-many relations. If you have navigation properties on both sides you must always deal with this problem.

Resources