get 'undefined' saveResult.entities after saveChanges [breezejs] - breeze

I tried to update one entity in my angularjs client using breezejs library. After calling saveChanges(), it can actually save back in the server and fetched on the client. However, the server did not return the response back. The saveResult.entities is undefined and pop up an error for me. When I took a look at the docs, it mentions 'Some service APIs do not return information about every saved entity. If your server doesn't return such information, you should add the pre-save, cached entity to saveResult.entities yourself'. Could anyone provide an example of how to do this?
This is the code when i am trying to do an update.
manager.saveChanges(entitiesToSave, null, (saveResult) => {
const savedRes = saveResult;
savedRes.entities = entitiesToSave;
return savedRes;
}).then(saveSucceeded);

On the server, you would need to construct the response for an update similar to the way it is for a create:
response.setContent(...); // entities
response.setStatusCode(HttpStatusCode.OK.getStatusCode());
response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());

Related

Get Response from CREATE_STREAM

We upload a document from SAPUI5 to our SAP System using the CREATE_STREAM Method of the oData Service in ABAP. The creation of the document works fine.
What we would like to achieve is to get the response back to SAPUI5. Especially when there is an error during the creation of the document in the backend.
In Frontend we use the uploadSet Control.
...oUploadSet.uploadItem(oItem);
In the Backend we create a message with
...lo_message_container->add_message( iv_msg_type = /iwbep/cl_cos_logger=>error
iv_msg_number = '018'
iv_msg_id = lv_msg_id
iv_add_to_response_header = abap_true
)....
We can find the created message in the error protocol of our gateway server (/IWFND/ERROR_LOG). But how can this message be retrieved in SAPUI5 and used in the MessageManger Control?
We tried the onUploadCompleted Control but we can't find any response data there.
Can somebody explain how the response or a message header from the CREAT_STREAM method can be used in SAPUI5?
The "new" UploadSet control is kinda half-baked imo. The response will get lost in some internal method. This internal method will then trigger onUploadCompleted and you get nothing but useless information.
Lucky for us we can easily overwrite this internal stuff. UploadSet has an aggregation Uploader. We have to provide our own Uploader. Problem solved. Here is the line that needs to be modified.
sap.ui.define([
"sap/m/upload/Uploader",
...
], function (Uploader, ...) {
return Uploader.extend("my.custom.control.Uploader", {
uploadItem: function (oItem, aHeaders) {
// beginning of the method. take it from the official sources
oXhr.onreadystatechange = function () {
const oHandler = that._mRequestHandlers[oItem.getId()];
if (this.readyState === window.XMLHttpRequest.DONE && !oHandler.aborted) {
// we need to return the xhr object. it contains the response!
that.fireUploadCompleted({ item: oItem, xhr: oXhr });
}
};
// .. rest of the method
}
});
});
Use it like this
<mvc:View xmlns:custom="my.custom.control" ....>
<UploadSet items="....">
.....
<uploader>
<custom:Uploader uploadUrl="......"
uploadCompleted=".onUploadCompleted"
uploadStarted=".onUploadStarted" />
</uploader>
</UploadSet>
Edit: Your own uploader also means implementing your own event handlers (uploadAborted, uploadCompleted, uploadProgressed, uploadStarted). See the official documentation for more information about the events.

SAPUI5 Send oData Request to Changeset

I would like to send a batch request to the changeset in the backend from my UI5 application. I did the following:
I created an Entity in my segw service. In the "changeset_begin" method I set the cv_defer_mode to true for my Entity.
In the frontend I tried to send a call to the backend. But somehow it doesnt work and I cant set a breakpoint in the ChangeSet. Are my syntax wrong? Thank you very much!
oDataModel.create("/MyEntitySet", { // in a loop, values are changed
properties: {
Key: item[i].getKey(),
Salesorder:"347854"
Department: "HR"
}
});
oDataModel.submitChanges({ // executed after loop
success: function (oData) {
oDataModel.refresh();
}
});
According to the API the method you are looking for is createEntry.
Creates a new entry object which is described by the metadata of the entity type of the specified sPath Name. For each created entry a request is created and stored in a request queue. The request queue can be submitted by calling submitChanges

How do you switch from SQL to Table Storage in Azure Mobile Services?

I've signed up for the free month trial of Azure, and I have created a Mobile Service. I'm using iOS, so I downloaded the model Todo app for iOS.
I am now trying to use Table Storage in the back end instead of a MSSQL store; I have found instructions on using Table Storage here: http://azure.microsoft.com/en-us/documentation/articles/storage-nodejs-how-to-use-table-storage/
However, my app is still storing todo items in the MSSQL storage. I've been told that I don't need to do anything in the client to make the switch, so I assume everything I need to do must be done in the node.js scripts. But I'm clearly missing something.
One thing that confuses me is that after I downloaded the generated node.js script for the Todo app, I didn't see anything in it that seemed to be explicitly talking to the MSSQL database.
Any pointers would be greatly appreciated.
EDIT:
here's my todoitem.insert.js:
var azure = require('azure-storage');
var tableSvc = azure.createTableService();
function insert(item, user, request) {
// request.execute();
console.log('Request received');
console.log(request);
var entGen = azure.TableUtilities.entityGenerator;
var task = {
PartitionKey: entGen.String('learningazure'),
RowKey: entGen.String('1'),
description: entGen.String('add something to TS'),
dueDate: entGen.DateTime(new Date(Date.UTC(2014, 11, 5))),
};
tableSvc.insertEntity('codedelphi',task, {echoContent: true}, function (error, result, response) {
if(!error){
// Entity inserted
console.log('No error on table insert: task created.');
request.respond(statusCodes.SUCCESS, 'OK.');
} else {
console.log('Houston, we have a problem. Entity not added to table.');
console.log(error);
}
});
console.log(JSON.stringify(item, null, 4));
}
tableSvc.createTableIfNotExists('codedelphi', function(error, result, response){
if(!error){
// Table exists or created
console.log('No error, table should exist');
} else {
console.log('We have a problem.');
console.log(error);
}
});
Mobile Services has the built in capability to handle talking to your SQL Database for you. When your script calls "request.execute()" that triggers whatever the request is (insert, update, delete, select) to be ran against the SQL database. Talking to Table Storage instead of SQL requires you to edit those scripts to explicitly talk to Table Storage (i.e. perform your insert, update, deletes, and reads). Today there is no magic switch which will change your "request.execute" from talking to SQL to talk to Table Storage. If you've already edited your scripts to talk to Table Storage and it's not working / you still see data stored in your SQL database, I would suspect that you are either still calling "request.execute" in your scripts, or you haven't pushed them to your Mobile Service (if you've pulled them down locally and then need to push them back to your service). If you've done all of the above, update your question with the Node.js script in question so we can see it.
As Chris pointed out, you are most likely still calling request.execute() from your table scripts. By design, this will explicitly talk to the MSSQL database you configured your application with. You will have to edit your table scripts to not perform "request.execute()" and instead interact with the TableService object.
If you follow the tutorial, and do the following:
1. Import the package.
2. Create the table service object.
3. Create an entity (and modify the variables to store the data you need)
4. Write the entity to your table service.
You should see data being written to table storage rather than SQL database.
Give it a shot and ping back, we'll help you out.

The Breezejs ZUMO example returns the inlineCount as undefined

I am trying to get the inlinecount from a breeze query. The results will come back, but the inlineCount property will be undefined. I captured the breeze query and results in Fiddler and they seem to be correct. The server returns the values in Fiddler with a count property added the the json results. I am getting the same results with my own app.
// Get all TodoItems from the server and cache combined
function getAllTodoItems() {
// Create the query
var query = breeze.EntityQuery.from('TodoItem')
.inlineCount();
// Execute the query
return manager.executeQuery(query)
.then(success).catch(queryFailed);
function success(data){
// Interested in what server has then we are done.
var fetched = data.results;
$log.log('breeze query succeeded. fetched: '+ fetched.length);
// Blended results.
// This gets me all local changes and what the server game me.
return manager.getEntities(todoItemType);
// Normally would re-query the cache to combine cached and fetched
// but need the deleted entities too for this UI.
// For demo, we returned every cached Todo
// Warning: the cache will accumulate entities that
// have been deleted by other users until it is entirely rebuilt via 'refresh'
}
}
The inlineCount property will be added by Breeze if you decorate your WebApi Get method with the BreezeQueryableAttribute or if you decorate the WebApi controller with the BreezeControllerAttribute. Otherwise, you can get the count by calling data.httpResponse.data.count.
You can prove this in the todo sample by launching the WebApi server and setting the uzeZumo variable to false in the config.js file. This will fetch the records from the WebApi. By default it'll fetch the data from Zumo.
Hope this helps.

CouchDB save doc uri incorrect

I am really scratching my head over this one. I am using cloudant as my couchdb provider and attempting to save a document to my db. I first establish what my db is in the following code.
db = jQuery.couch.db("https://fullscore.cloudant.com/fullscore");
I do a console.log and see that the URI and name are correct in the object.
db.saveDoc(doc, {
success: function(data) {
console.log("posted");
},
error: function(status) {
console.log("failure");
}
});
However when I look at the post, it posts to: https://cloudant.com/https%3A%2F%2Ffullscore.cloudant.com%2Ffullscore/
Which as you can see is totally wrong. Obviously there is something built in to append onto cloudant.com ... anyone know how this can be overridden? Or perhaps its some other problem? I'm getting a 404 error.
--Ashley
To clarify the exact code, you need to set the URL prefix on your couch object, then use just the db name:
$.couch.urlPrefix = "https://username.cloudant.com";
var db = $.couch.db("dbname");
I'm guessing you're passing the full database URL in a place where you're only supposed to pass the database name (i.e. the latter "fullscore" part in https://fullscore.cloudant.com/fullscore"). You've probably already set up the host name at some earlier point in your program.

Resources