I have a dilemma regarding Core Data and syncing data with server.
I wrote an app which uses Core Data, don't use id attributes, everything is set with relationships. Most of data is being generated on device and should be sent to server as backup. On the other hand, there is some data that can be reused among users and I want to have control over it, i.e. modifying, deleting, adding.
Question
When sending data to server, what's prefered way of dealing with relationships? In my opinion, it would be very inefficient to think in terms of Core Data, sending all relation objects to server and then deal with them if they already exist on server. So, using uniqueId is obligatory? Generating ones on server which will be shared and others on devices? Is there any other approach?
Thank you.
Assuming that the server database works with foreign keys, one common solution is to introduce id attributes and set them to some invalid state for new objects. For example, for new relationships you could generate an arbitrary number of unique "invalid" ids by using negative integers. The server would have to then assign new (server-unique) ids and send them back to the client. Of course, when importing data from the server, you replace foreign keys with relationships.
So if you have potentially more than one device trying to modify data also used by other users or devices, the server will have to be part of the solution. Otherwise, you could just generate unique IDs so the server can store the relationships.
Related
I am looking for the proper way for a swift iOS app that relies on, in my case: AWS but has a local persistent data store so that every possible feature of the app can be used offline.
So far, I went from a pillar or two of Core Data to a full core data stack and it is becoming difficult to foresee how to coexist with AWS DynamoDB. While DynamoDB is of a NoSQL structure, Core Data in the way I have set it up is that of a SQLite persistent data store.
I need to eventually download tables and primarily use AWS for most situations where users are online, but if they want to work offline, I need to be prepared. Perhaps I should try to create a singular User entity, because why would I want to store other users offline? Then once internet is active, I could try to push it to my DynamoDB Users (plural) table.
I have created Entity's in Core Data such as Users, Authors, Profile.
In the scenario a user opens the app and has no internet access, I am planning on inserting a Users entity and my goal is to correctly populate Authors and Profile, because this offline end user is definitely a User, and I want to setup at least a Profile for them as well so that they can later tweak with customizations.
I have maybe too many relationships. I want to do this correct.
In simple situations, I understand a Person Entity might have a father, mother, child and how they can all fit nicely into Person, but since I have entities with enough unique attributes that I thought I need to create their own entities,
How should I go about creating an entity that certainly makes a User/Users record and establishes a Profile?
Short answer is this:
Core Data is your local cache whether you are offline or online. If you are online then the app should refresh the Core Data cache when appropriate.
When offline the app should not update the cache.
The User Interface in either case is identical. The user interface feeds from the Core Data cache ONLY.
I suggest watching my talk on MVC-N that is hosted by realm.io.
iOS newb building an app to work with a website. Ultimately, I want to keep the app and backend on the website in sync.
Photos are saved on the website using the ID of the item. For the app, I would also like to save the photo with a unique number linked to the item.
On the website, the id of each item is simply the auto incremented number in a MYSQL table.
My understanding is autoincrementation is impossible in Core Data but it does create unique identifiers for each managed object.
How would I get and store this number in the core data database at the time the item is created for later retrieval?
Alternatively has anyone discovered a way to auto-increment in core data so as to give items numbers that could be used for storing photos. It would be nice to have a similar naming scheme for photos created by the app and those created through the website.
There is no 'built in' solution for creating an auto-incrementing id in Core Data.
One important thing you should recognize is that Core Data is an object graph not a relational database. This is very important in understanding how you should approach design with Core Data.
Yes, Core Data does create unique identifiers for objects in the form of GUIDs - so it's not a number, but rather 32 hexadecimal digits (Globally unigue identifier).
You can write a method that will get the next number in a sequence for an entity, but Core Data will not do it for you.
You may find the information in this question useful: Set auto increment in Core data iOS. I would not attempt to use NSManagedObjectID. This value can change.
My suggestion is that you allow the MySQL database to assign the id's and simply store that id in a number property in the Core Data object. For items originating in the app leave the id property blank until it has been sent to the MySQL database for persistence. Then, retrieve the Id that the database assigned it and set it to the Core Data object's property.
I want to remove all entities which are not represented on the server anymore (e.g when another client deletes it).
My current approach is to delete all entities from a specific type which are not returned after a query anymore:
Get and cache all local entities from specific type
Make the query
Compare old entities with new entities which are returned from the query and detach it from entity manager
This seems a little work for me and i wonder if there not an easier way (maybe breeze already has something) to do that?
It's a good question. We refer to these types of entities as "ghosts". They are entities that are queried from a server by one user and later deleted by another user. The entities on the first client have now become 'ghosts'.
We have an existing feature request that would automatically 'detach' these if and only if a primary key requery occurs. The reason for this is that unless the entity was fetched by primary key we cannot determine that it is a ghost. We have not yet implemented this feature but are considering it for one of the near term releases. Would this feature be of use to you?
We've an MVC web app which has a Claim management wizard (similar to a typical Order entry stuff). Claim can have multiple Items and each Item can have multiple files related to it.
Claim --> Items --> Files
While adding a new Claim - we want to allow the user to add one or more items to it and also allow file upload for those items. But we want to keep everything in memory until the Claim is actually saved - so that if the user doesn't complete the Claim entry or discards it, no database interaction is done.
We're able to handle data level in-memory management via session. We serialize the Claim object (which also includes a Claim.Items property) in session. But how to manage files?
We store files in < ClaimID >\< ItemID > folder but while creating a new
claim in memory we don't have any IDs until the record is being
saved in the database (both are auto-increment int).
For now, we've to restrict the user from uploading files until a Claim is saved.
Why not interact with the database? It sounds like you're intending to persist data between multiple requests to the application, and databases are good for that.
You don't have to persist it in the same tables or even in the same database instance as the more long-term persisted data. Maybe create tables or a database for "transient" data, or data that isn't intended to persist long-term until it reaches a certain state. Or perhaps store it in the same tables as the long-term data but otherwise track state to mark it as "incomplete" or in some other way transient.
You could have an off-line process which cleans up the old data from time to time. If deletes are costly on the long-term data tables then that would be a good reason to move the transient data to their own tables, optimized for lots of writes/deletes vs. lots of reads over time.
Alternatively, you could use a temporary ID for the in-memory objects to associate them with the files on the disk prior to be persisted to the database. Perhaps even separate the file-associating ID from the record's primary ID. (I'm assuming that you're using an auto-incrementing integer for the primary key and that's the ID you need to get from the database.)
For example, you could have another identifier on the record which is a Guid (uniqueidentifier in SQL) for the purpose of linking the record to a file on the disk. That way you can create the identifier in-memory and persist it to the database without needing to initially interact with the database to generate the ID. This also has the added benefit of being able to re-associate with different files or otherwise change that identifier as needed without messing with keys.
A Guid shouldn't be used as a primary key in many cases, so you probably don't want to go that route. But having a separate ID could do the trick.
First, Thank you for any help provided.
I have an iOS leveraging CoreData to retain various presentations, this data comes from a sqlite file and there is no server connection.
I will have to be able to provide App updates (via appstore), this update may add more data to the database.
The tricky part is that it can not simply overwrite the current database, there are a few user tables that I will not like touched.
Please provide any information I should consider when accomplishing this or any links are greatly appreciated.
Thank you.
Given your app has no server connection, you will have to rely on shipping data within the updated application itself. I would recommend using a plist file or define your own xml or json structure. You can then read this data to create/update core data nsmanagedobjects.
It looks like someone in the past was using plist->coredata on SO
Would you have relationships between user created data and shipped data?
If not, you might go the route of connecting two stored to the persistent store coordinator. The shipped store would be read-only. The store with user created data would be read-write. You can use this approach, too, if you have relationships between shipped and user-created objects, but it's a lot more complicated, since CoreData doesn't manage cross-store relationships for you, and you'll need to write your own logic (doable, but not straight forward).
If you need to have relationships between shipped and user-created objects, you can still ship a CoreData store. When the app launches for the first time (no user-created objects), you copy the store to the Documents folder and user this store to create your CoreData stack. User created objects will be added to this store. Once you have new 'shipped' objects (i.e. a new store in the app-bundle), you'll have to manually migrate that stores data into the store that the user has changed. You'll have to be able to find
(1) objects that need to be deleted
(2) objects that need to be updated (changed)
(3) objects that need to be added
If you mark your shipped objects with a special flag such that you can tell if it's a user created object or a shipped one, that would be doable. You also have to have some sort of ID to be able to tell which objects in the new store correspond to which ones in the existing (old) store.
You do not need to go the route of using plists. In fact, I'd recommend against it. You can easily open two stores at the same time. Either to use both stored, or just to migrate objects from one store to the other store.