I don't have access to an OData provider just a simple REST api with json and I need to store the data locally (on the mobile device websql) in different tables reflecting the backend model. Following the Edmunds example I have got the entity and the relationships working from the REST api. How can I make it work the same way from the data stored locally. I would like to fetch the data from the local DB and recreate my entities, any advice would be appreciated thanks.
After you have queried the data thru the REST api, just export the EntityManager to local storage. Something like this
var changesExport = myEntityManager.exportEntities();
ok(window.localStorage, "this browser supports local storage");
var stashName = "arbitrary name for storage area"";
window.localStorage.setItem(stashName, changesExport);
This data can later be reimported into any existing EntityManager, and then queried locally by simply reimporting the data.
importedData = window.localStorage.getItem(stashName);
anotherEntityManager.importEntities(importedData);
Related
How will the json data sent over from external Api be cached into the Falcor-Model? Also, how to specify in the Model to hit the external Api again if data not present in the cache?
My doubt was partially answered in one of the posts:
How does Falcor cache data in the server side?
So now I understand that Falcor-Model cache works only at the client side, which is fine. But how will the Model work if the data is not present in the cache?
var model = new falcor.Model({source: new falcor.HttpDataSource('http://localhost/rating.json') });
model.
get("rating").
then(function(response) {
document.getElementById('filmRating').innerText = JSON.stringify(response.json.rating,null, 4);
});
Here the response is a json object, which can be put into a Falcor-Model cache and stored globally in the client side. But how can the Model be triggered again if data not present in cache?
The main advantage of using Falcor is that you should not have to care whether data is present in cache or fetched from the server, because model.get() which fetch all the data missing in the cache from the server by making an HTTP request.
So, the first model.get(path) query will fetch from server, and put response in cache. If you call model.get(path) again, it will be served from the cache.
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}' )
I am using Parse.com as backend for an iOS application. When I get all the remote objects from a relation and pin them, I can access them locally later.
However, I want to use the "updatedAt" property on a Parse object to only fetch updated objects remotely and update the local datastore.
How it is done:
query.whereKey("updatedAt", greaterThan: lastDate)
let results = try query.findObjects()
try PFObject.pinAll(results)
Let's say I have 10 objects locally, and the remote query only returns 1 object. After pinning the one returned object, the other 10 local objects are removed. The result is that only the one new remote object is saved locally.
Is it possible to use the "updatedAt" key to only fetch new objects and still have all objects in the local database? How is this done?
Thanks in advance!
I need to synch up Core Data on phone with MYSQL database on server. I have gotten as far as capturing JSON feed in iOS in array. My question is, what is the best way to compare and sync up the items?
I know there are many SO posts and tutorials on syncing however the comparison is often brushed over. Once you have the JSON feed in an array and also have a managed object context, how do you compare one entry against the other?
My strategy is to give each locally saved object (record) a local id. Then when syncing occurs if the local object (record) has no server id, add it to the server table. However, I'm not sure how that works with the managed object context.
Do you iterate through the local records and compare them against server records?
Or do you iterate through the JSON array against the local managed object context?
for (NSDictionary *item in names) {
id serverid = [item objectForKey:#"serverid"];
// .... check against something in managed objectcontext
if (!items.serverid ) {
///insert on server and also provide obtained serverid to managedobjectcontext
}
}
Would appreciate any insights or suggestions.
Tim Isted addressed a similar issue in his exceptional talk at WWDC 2013.
You should watch the whole thing, because it's pretty awesome. However, the relevant part for this topic starts about 12:43 into the presentation.
I'm trying to sync my data from a web service in a simple way. I download my data using AFNetworking, and using a unique identifier on each object, I want to either insert, delete or update that data.
The problem is that with Core Data you have to actually insert objects in the NSObjectManagedContext to instantiate NSManagedObjects. Like this:
MyModel *model = (MyModel *)[NSEntityDescription insertNewObjectForEntityForName:#"MyModel" inManagedObjectContext:moc];
model.value = [jsonDict objectForKey:#"value"];
So when I get the data from the web service, I insert them right away in Core Data. So there's no real syncing going on: I just delete everything beforehand and then insert what's being returned from my web service.
I guess there's a better way of doing this, but I don't know how. Any help?
You are running into the classic insert/update/delete paradigm.
The answer is, it depends. If you get a chunk of json data then you can use KVC to extract the unique ids from that chunk and do a fetch against your context to find out what exists already. From there it is a simple loop over the chunk of data, inserting and updating as appropriate.
If you do not get the data in a nice chunk like that then you will probably need to do a fetch for each record to determine if it is an insert or update. That is far more expensive and should be avoided. Batch fetching before hand is recommended.
Deleting is just about as expensive as fetching/updating since you need to fetch the objects to delete them anyway so you might as well handle updating properly instead.
Update
Yes there is an efficient way of building the dictionary out of the Core Data objects. Once you get your array of existing objects back from Core Data, you can turn it into a dictionary with:
NSArray *array = ...; //Results from Core Data fetch
NSDictionary *objectMap = [NSDictionary dictionaryWithObjects:array forKeys:[array valueForKey:#"identifier"]];
This assumes that you have an attribute called identifier in your Core Data entity. Change the name as appropriate.
With that one line of code you now have all of your existing objects in a NSDictionary that you can then look up against as you walk the JSON.
The easiest thing to do is to restore the Json to a entity that maps properly to it. Once you've mapped it, determine if a object matching the entities ID exists already, if so then fetch the entity and merge changes. If not, create a new entity in Core Data and restore the Json to it.
I'm building a app were I do client side syncing with Evernote. They keep a syncUpdate number on all of their objects and at the server level. So when I start my sync I check if my clients syncUpdate count is less than the servers. If so, I know I am out of sync. If my updateCount is at 400 and the server is at 410, I tell the server to provide me with all objects between updateCount 400 and 410. Then I check if I already have the objects or not and perform my update/create.
Every time a object is modified on the server, that objects updateCount is increments along with the servers.
The server also keeps a time stamp of the last update, which I can check against also.