core data structure - ios

Im about to add the persistence layer to my application, and i decided to give core data a go. Currently i map all my models to entities, which seems to work quite well. But in my current implementation i use something i call "collections" (of models) for example i have a collection of tile slots in a game.
this SlotsCollection class has methods like findNextInSameRow() findAvailableSlot() etc. What ive done with core data is i have created a Game entity and added a to many relationship to the Slot entity, Is there a way to define a class which the collection of slots should be instantiated with so i can put my logic inside that? Or is there a better way for me to structure things. I guess i could create "managers" inside my Game entity and hand in the slots when initialized
SlotManager* manager = [SlotManager alloc] initWithSlots:self.slots];
Slot* slot = [manager findAvailableSlot];
Also after i "migrated" all my models to entities, i have alot of entities that do not have any attributes but only hold references to other entities. Im abit afraid im using a wrong mindset when structuring the core data.

The class that has the collection should have the logic for that collection.
If you have a 1-to-many relationship from A to B, then you'd put the logic about this relationship into class A — and possibly some of it inside class B (depending on your needs).
Note: If you're iterating through relationships, you need to be aware of faulting behavior etc. Whenever Core Data has to do actual database work, you incur a performance hit. That's no different that plain old SQL. If you don't have to "go to disk" things are very fast. If you're using fetch request you will always do database work, and things will always be (relatively) expensive.

Related

Core Data design principles

I just started reading this guide: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreData/KeyConcepts.html#//apple_ref/doc/uid/TP40001075-CH30-SW1
And it basically has (in my opinion) two big contradictions:
I get them both, but basically, if I follow the first "implement a custom class to the entity from which classes representing subentities also inherit"-statement, then ALL my entities will be put in the same table. Which could cause performance issues, according to the NOTE.
How big of a performance hit would I run into of it create a "custom super entity"?
You can use the inheritance mechanism to get a default database structure. From your link:
If you have a number of entities that are similar, you can factor the common properties into a superentity, also known as a parent entity.
There is no contradiction. The documentation is just telling you what the database structure is going to be when you use a certain facility. (And it is the standard database table idiom for inheritance.) Using the entity inheritance mechanism automatically declares and implements default parent-child class inheritance functionality along with a parent table. Otherwise you do any parent-child class inheritance declaration and implementation by hand. Each comes with certain performance and other characteristics.
Design involves tradeoffs between costs and benefits over multiple dimensions. "Performance" itself involves multiple dimensions, and has no meaning outside of given application usage patterns. Other dimensions relevant here include complexity of both construction and maintenance.
If you query about entities as parents sufficiently frequently then it can be better to have all parent data in its own table. But if you sufficiently rarely ask for the parent data while querying about a given child type or if you sufficiently frequently need both child and parent data then it can be better to only have parent data in the child tables or table. But notice that each design performs worse at the other kind of query.
The first is talking about sub-entities. The second is talking about subclasses. These are 2 different hierarchies.
One use for sub-entities is if you have a table where you want to show cells displaying different entities. By making them sub-entities, you can fetch the parent entity and all sub-entities will be returned. This is actually how the Notes app shows the "All Notes" cell above folders, that is actually displaying the Account entity, and both Account and Folder are sub-entities of NoteContainer which is what is fetched. This does mean all of the rows are in the same table, but personally I have not experienced any performance problems but it is something to keep in mind when modifying the entities in other ways like indexes, relations or constraints for example.
I'm not familiar with this quirk of SQLite, but modeling base class/subclass relationships are usually done with different tables. There is one table that represents the base class which contains attributes common to all derivative classes (Vehiclea) and a different table for each subclass which contain attributes unique to that subclass (Cars, Trains, Airplanes).
Performance is no better or worse than any entity normalized across different tables.

Learning Core Data. Entities, Adding and Loading

So, I'm trying to use Core Data to save instances of a "Screenshot" class, which consist of:
NSString *note;
NSData *screenshot;
NSData *thumbnailOfScreenshot;
NSTimeInterval date;
In my Core Data file, i have two entities because i want to fetch the large images only when necessary, and only 1 at a time (it is to be used in a UITableView).
Entity 1 is called Screenshot and consists of the 4 attributes above, whereas the *screenshot is transient. This entity also has a to one relationship with entity 2(an int called index).
Entity 2 only has 1 attribute which is a Binary data field for the Large images. Also a to one relationship with entity 1.
So, my first question: Is this remotely close to being correct? I'm a little unsure if i even need the Transient attribute "screenshot", in entity 1. And i am also confused if i need to create a new class for entity 2, which seems abit odd, since it will just contain the images.
For now, I'm only trying to add and load instances to and from the DB.
Here is how i (think) i add an instance to the DB, but i am not sure it actually puts it in the DB right away?:
Screenshot *s = [NSEntityDescription insertNewObjectForEntityForName:#"Screenshot" inManagedObjectContext:context];
I am in over my head, so any help will be appreciated. I have read several guides, but none was targeting something similar to this.
Transient properties are not saved to Core Data (they are neither retrieved nor saved out from the backing store). They are most often useful for calculating some sort of property based on stored properties (e.g. I use them for queries based on the first letter of a person's last name -- I'm storing the full last name, but the firstLetterOfLastName is a transient property -- but one that I can order results on since Core Data knows about it).
If I'm understanding your model correctly, you likely want no transient properties at all.
I also don't think you need an entirely new model for your "large images". You can instruct Core Data to optimize it's backing store for large binary attributes by turning on "Store in External Record File". You'll find this in the Data Model Inspector pane underneath where Transient and Optional are set. This will keep the actual backing DB snappy, but allow Core Data to retrieve these large binary attributes and you may still work with them seemlessly with a Core Data NSManagedObject instance.
Also, in general, do not relate items by an "index" value of some other stored Core Data object. There's plenty of reasons to do so, but in general, this is what Core Data relationships are for. If "Movie" has multiple "Screenshots", for e.g, you would have a relationship on a Movie instance called "screenshots" that you simply add each screenshot to (it's effectively an NSMutableSet as far as you care).
Core Data is an object graph, not a relational database. If you add the same object instance to two relationships on different owner-object instances, you aren't duplicating the child-object -- Core Data does all the work to interrelate them for you (assuming your models are setup in a good way).
I'd rethink this. I think a single entity is enough for this. I'd either add a BOOL value named 'large' and do a fetch when "large = NO" to get the small images. Alternatively, if you want more control, add a 'pixels' or 'megapixels' field which describes the size of the image. Then you can fetch where 'pixels > 3000000' for instance.
If you have a special relationship between two images (i.e. one image is a thumbnail of another), I'd just add a relationship to another Screenshot entity.
Alternatively, you could also make one Entity the "Parent Entity" of the other (see the Data Model inspector when you have an entity selected).
You're on the right track. Keep thinking about how you want to use your entities. This should help you describe the relationships better. Quite often I write the code that uses the entities before I define them in a data model. This lets me end up with cleaner interfaces and less overlap between entities.

CoreData object modeling with multiple timeframes for weather data

I do have some JSON file http://jsonblob.com/530664b3e4b0237f7f82bdfa I am pulling from forecast.io.
I am little confused how I should be creating my CoreData entities and relationships.
In below setup, I made my Location entity as the parent entity and created a separate entity for Currently, Minutely, Hourly, Daily. However I have decided it's best to hold all the information regarding the weather data in one entity, so I created a Data table for that purpose and tied it to Daily and Currently in the image below.
Before going further, I paused and would like to get a second opinion on it. Is this a valid way of going forward with this?
EDIT: Based on Wain's response I changed my model to this
Currently Minutely and Hourly add little value as they don't have any attributes or relationships. It's also generally easier to add a type attribute rather than having a number of sub entities because you can easily filter the type using a predicate while doing a fetch. If you're going to add more in the future then there could be a case for keeping sub entities.
Once the entities are trimmed down then you only have a Location and Data with a relationship. You should make that relationship bi-directional so that Core Data can manage the data store contents better. (this applies to all relationships, even if you keep the sub entities you already have).
Other than that, fine :-)

Inherit from SPManagedObject

In Simperiums iOS/OSX tutorial you say, each modeled object should inherit from SPManagedObject.
I didn't try it yet, but doesn't that lead to one big table in the SQLite database that contains a union of all fields of all modeled managed objects?
Yes, under the hood Core Data will tend to create a bigger table. Generally performance will suffer more from relations though, not inheritance:
Using Parent Entity in CoreData Models
We've done integrations with fairly complex inheritance hierarchies and didn't see any immediate issues with a fair amount of data.
Having said that, should you need more control over your table structure, you can avoid having a single parent for all your objects and instead either:
Manually add the ghostData and simperiumKey attributes to the objects you want to sync, and ensure their class is SPManagedObject (or ensure their custom class inherits from SPManagedObject), or
Create more than one parent entity with ghostData and simperiumKey attributes, and inherit from those for the parts of your model where it makes sense, depending on how you'd like the underlying tables to be structured.

Is it difficult to manage iInheriting a client dataset from another?

Say I have a client dataset CDSPerson that acts as a wrapper around a Persons database table. Say I have another table, PersonBenefits, that joins 1:1 back to the Persons table.
Say I wrap a Delphi class around CDSPerson, PersonClass, and another class around CDSPersonBenefits, PersonBenefitsClass, to read and write records. PersonBenefitsClass inherits from PersonClass so it can provide data from both tables. I'd like to be able to write data back to either table through PersonBenefitsClass.
Has anyone developed a clean way to handle the SQL query, provider flags and commit logic in the inherited class so that (a) fields stay aligned with the parent class and (b) both database tables can be updated?
Is there a reference for this that I can't find? Is this just a bad idea? I'm using Delphi 2007.
If you're going to develop a business-object-to-database mapping framework, (commonly known as ORM, Object-Relational Mapper,) you're going to need to put in a bit of architecture to make relationships like this work properly. Here's one way to do it:
PersonClass and BenefitsClass both inherit from BusinessObjectClass. BusinessObjectClass is a base class that contains the general logic to interact with the dataset. It has a list object of some sort that contains a list of relation objects.
Each relation object is a special object that contains either one or a list of BusinessObjectClass descendants, plus extra data describing the foreign-key relationship between the two tables. When BusinessObjectClass does its queries and its updates, it needs to iterate through all its relation objects and have them do their own queries and updates as appropriate.
In your composite object, (PersonWithBenefitsClass,) in the constructor, call inherited and then set up a relation object that describes the related BenefitsClass. Make sure that any inserts of new objects are done in the right order to preserve referential integrity.
That's the basic idea. (One basic idea. There are probably plenty of other ways to do it.) I'll leave the details of exactly how you implement it up to you.

Resources