I implemented the update operation for an oData service. When I tried to call it via my SAPUI5 application, I got the following error message:
'XXX_GET_ENTITY' not implemented in data provider class
That's true - I did not yet implement the GET ENTITY method.
However, can someone tell me why I need this one for an update?
The JS coding for the service request is created this way:
oDataModel.update("/EntitySetName(<key>)", oPayload, {
success: function(oData) {
...
},
error: function(oError) {
...
}
});
I appreciate every hint / explanation.
The default update method for the ODataModel is a patch/merge, see the documentation from the ODataModel class:
Trigger a PUT/MERGE request to the OData service that was specified in
the model constructor.
The update method used is defined by the global defaultUpdateMethod
parameter which is sap.ui.model.odata.UpdateMethod.Merge by default. [...]
The default implementation of the PATCH_ENTITY method calls the READ_ENTITY first and then merges the incoming data with the retrieved data to allow for partial updates. From the comments in this method:
*-a patch request is a partial update of an entity. All provided components are patched.
*-The default implementation of patch_entity performs a read before update [...]
To do a PUT request, set the updateMethod property to sap.ui.model.odata.UpdateMethod.Put.
Related
I'm trying to implement odata v4 for my current master detail app which was using odata v2.
In my app, I used some statements like these.
this.getOwnerComponent().getModel().metadataLoaded().then(fnSetAppNotBusy);
var oContext = this.getModel().createEntry(sPath, {
properties: {
Name: "ABC",
Age: "20"
},
success: this._fnEntityCreated.bind(this),
error: this._fnEntityCreationFailed.bind(this)
});
I see in this document Changes Compared to OData V2 Model, odata v4 has replaced metadataLoaded with "corresponding methods".
I have searched and found some but am not sure if these methods are correct. Can someone please confirm?
And I can't find method createEntry in oDataModel v4, so how can I implement the same logic as I did with odata v2?
Thanks
Hmm. The creation is covered in this example:
https://sapui5.hana.ondemand.com/sdk/#/sample/sap.ui.core.tutorial.odatav4.06/code
(Basically, you execute the creation on binding/context level)
As for onMetadataLoaded, you may use getMetaModel() and then use the „appropriate” functions with promises, but I’d go as follows: grab your binding, which is the one you are waiting for, and attach to the event dataReceived. E.g.,
oTable.getBinding('items').attachEvent('dataReceived', function(){...})
The API docs explicitly states that this event is to be used for busy indicators:
https://sapui5.hana.ondemand.com/sdk/#/api/sap.ui.model.odata.v4.ODataListBinding/events/dataReceived
I have a OData model and data is as follows
Here, Under ZRECRUITMENT_TRACERRzSet(1), I have "toCandidates" which is Association and it has item level data.
How can I access it's values in the controller.
I tried using
oModel.getProperty('/ZRECRUITMENT_TRACERRzSet(1)/toCandidates')
But it's not helping.
You need to set the 'expand' property in your binding, so whenever the request is sent to the OData service, the "toCandidates" node will come with the data in the response, and not the URL only. Then your getProperty(...) will give you the data.
Whenever you are binding your data you need to do something like this (for example with ElementBinding):
oMyControl.bindElement({
path: "/ZRECRUITMENT_TRACERRzSet(1)",
parameters: {expand: "toCandidates"}
});
Is there a way for the SAPUI5 TreeTable to not call the OData web service on each node expansion? I've tried setting the operationMode parameter to client as part of the data binding, but it still retrieves the data via individual web service calls for each node expansion. Currently running SAPUI5 1.28.45.
The model is of type sap.ui.model.odata.v2.ODataModel and set globally. I've tried configuring the default operation mode on the model without success and toggling batch mode without success. It's set up for two-way binding as well.
I'm currently setting the operation mode as below with no luck:
this._oTable.bindRows({
path: '/EventSet',
filters: self._aFilters,
parameters: {
countMode:'Inline',
operationMode: sap.ui.model.odata.OperationMode.Client // Seemingly ignored
}
});
You could try to use JSONModel Binding instead of ODataModel Binding.
You can get the content of the EventSet with a Read function https://sapui5.hana.ondemand.com/#docs/api/symbols/sap.ui.model.odata.v2.ODataModel.html#read
Then in the Success function you take the result, create the JSONModel, convert the data into something that the TreeTable can use, set this to the JSONModel, set the JSONModel to your TreeTable Object (eg.):
this._oTable.setModel(oYourJsonModel, sModelName);
this._oTable.bindRows({
path: "/",
parameters: {
arrayNames: ["additionalData"]
}
});
Here you can find information about JSON Tree Binding:
https://sapui5.hana.ondemand.com/explored.html#/sample/sap.ui.table.sample.TreeTable.JSONTreeBinding/preview
Hope it helps.
Best regards,
Adrian
I am playing around with a OData service and I am very confused when to use this
var oModel = new sap.ui.model.odata.ODataModel("proxy/http/services.odata.org/V3/(S(k42qhed3hw4zgjxfnhivnmes))/OData/OData.svc");
this.getView().setModel(oModel);
vs
var oModel = new sap.ui.model.odata.ODataModel("odatserviceurl", true);
var productsModel = new JSONModel();
oModel.read("/Products",
null,
null,
false,
function _OnSuccess(oData, response) {
var data = { "ProductCollection" : oData.results };
productsModel.setData(data);
},
function _OnError(error) {
console.log(error);
}
);
this.getView().setModel(productsModel);
I have two working example using both approach but I am not able to figure out why using read method if I can achieve same with first version. Please explain or guide me to the documentation which can clear my confusion.
Ok, lets start with the models:
JSON Model : The JSON model is a client-side model and, therefore, intended for small datasets, which are completely available on the client. The JSON model supports two-way binding. NOTE: no server side call is made on filtering, searching, refresh.
OData Model : The OData model is a server-side model: the dataset is only available on the server and the client only knows the currently visible rows and fields. This also means that sorting and filtering on the client is not possible. For this, the client has to send a request to the server. Meaning searching/filtering calls odata service again.
Now, lets look at scenarios where we will use these models:
Scenario 1: Showing data to user in a list/table/display form. Data manipulation is limited to searching and filtering. Here, I would use oData model directly to controls as only fetching of data is required.( your method 1) (NOTE: One way binding). Remember here all changes require a call to server.
Scenario 2: I have an application which has multiple inputs, user can edit changes, also some fields are calculated and mandatory. All in all, many user changes are done which may be temporary and user might not want to save them. Here, you dont want to send these temporary changes to backend as yet. You way want to manipulate, validate data before sending. Here, we will use JSON Model after reading data from odata model ( your method 2). Store the changes in local JSON model, validate and manipulate them and finally send the data using Odata create/update. Remember here all changes DO NOT require a call to server as data is present in local JSON MODEL.
Let me know if this helps you. :)
EDIT : Additional Information :
As per your comment :
Documentation says oModel.read' trigger get request but new sap.ui.model.odata.ODataModel("proxy/http/services.odata.org/V3/(S(k42qhed3hw4zgjxfnhivnmes))/OData/OData.svc")` does the same thing so why and when to use oModel.read
Here, is where you misunderstood. The code
new sap.ui.model.odata.ODataModel("proxy/http/services.odata.org/V3/(S(k42qhed3hw4zgjxfnhivnmes))/OData/OData.svc") will NOT send a read/get Request. It calls the odata services and fetches the metadata of the service. A service can have multiple entities.
For example: the service :http://services.odata.org/Northwind/Northwind.svc/ has mutiple entity sets such as Categories, Customers, Employees etc. So, when I declare : new sap.ui.model.odata.ODataModel("http://services.odata.org/Northwind/Northwind.svc/") it will fetch the metadata for service (not actual data). Only when you call the desired entity set, it will fetch the data. The Entity set is specified :
When you call the read method ( like you have specified '/Products')
Bind the entity set name directly to control like to List,Table etc ( items='{/Products}' )
We are trying to develop our own EF provider for our legacy APIs. We managed to get "GET/POST" operation working successfully.
However, for operation "PUT/MERGE", the method "CreateDbCommandDefinition" (of DbProviderServices implementation) fires twice. One with "DbQueryCommandTree" and another with "DbUpdateCommandTree".
I understand that it needs to fetch the entity prior to update it (for change tracking I guess). In our case, I don't need the entity information to be fetched prior to update. I simply want to call our legacy APIs with the entity sent for update. How can we strictly ask it to not to do the work of "DbQueryCommandTree" (and do only the work of "DbUpdateCommandTree") when I working with "PUT/MERGE" operations.
The client code looks something like the one below:
public void CustomerUpdateTest()
{
try
{
Ctxt.MergeOption = MergeOption.NoTracking;
var oNewCus = new Customer()
{
MasterCustomerId = "1001",
SubCustomerId = "0",
FirstName = "abc",
LastName = "123"
};
Ctxt.AttachTo("Customers", oNewCus);
Ctxt.UpdateObject(oNewCus);
//Ctxt.SaveChanges();
Ctxt.SaveChanges(SaveChangesOptions.ReplaceOnUpdate);
}
catch (Exception ex)
{
Assert.Fail(ex.Message);
}
You will have to write your own IDataServiceUpdateProvider to make this happen. For EF, the in built EF update provider does 2 queries - one to get the entity which needs to be modified and one for the actual modification. We are planning to make this provider public in our next release, so folks can derive from it and just override one or more methods. But for now, you will have to implement the interface yourself.
For PUT/MERGE requests, WCF Data Services calls IDataServiceUpdateProvider.GetResource to get the entity to update. In your implementation of this method, you can return a token that represents the object that need to get modified (you will have to visit the expression tree that gets passed in this method to find out the entity set and the key value of the entity in question).
In SaveChanges, you can push the update based on the token. That way you can avoid one round trip to the database.
Hope this helps.