Finding the entities of a CoreData model at runtime - swift

I have an macOS app being developed in Xcode (8.3.2) in SWIFT.
I have a CoreData model with a number of entities and an identifier (myidentifier).
I want to be able to identify the entities of the model programatically at runtime so that I can iterate through the entities and store data being sourced from a range of JSON files based on the data within the JSON file.
To date I have been creating entities and then writing a class for each entity to both save and fetch the data. It is working perfectly and as expected. However, if I continue like this I will end up with about 50 different entities and their associated class files (note that some while entities use a one to many relationship, the majority do not).
I would like to create a single class that will enumerate through the numerous entities of the model and store the relevant data (as well as its associated fetch routine).
I should also note that I am using NSManagedObject subclasses for each of the entities.
How do I obtain a NSManagedObjectModel reference to the model that I am using for the app? I can't seem to find the right mechanism to allow me to do this. Can I do this using the model identifier?
My thinking is that if I can then use entitiesByName I can make use of the resulting [String: NSEntityDescription] to then access my entities and enumerate as needed.

You could use mergedModel(from bundles: [Bundle]?) (see the documentation here, specfying Bundle.main to get the main bundle. Alternatively, your NSManagedObjectContext will have a reference to the persistentStoreCoordinator which will itself have a reference to the managedObjectModel.
Note that NSManagedObjectModel has an entities property so you can use:
for myEntity in myModel.entities { ... }
rather than using entitiesByName.

Related

Core Data Coding Pattern

I have been working with C# using a repository design pattern with Entity Framework (EF) that allows me to interact with the database using a generic class for each table.
This repository has all the functions that I would need such as: Adding a new entity into the database, updating an existing entity, deleting an entity, saving the context and so on...
Take, for example, I have an entity called 'Person' in the database. I would create a new class called PersonRepository which had all the functions I would need to change/add a value to the database.
As a result, to interact with the database, you create an instance of the repository class. This then allows you to call the functions of this class which in turn interacts with the database. The idea of this pattern is that all your database calls for an entity are isolated into a single class, this improves testability and separation of concerns.
I am learning how to use Core Data in my Swift programs and it appears to be similar to that of EF in C#. I have created the entities in the .xcdatamodel file and created the associated Cocoa Touch class via the Editor > Create NSManageedObject subclasses option.
I used the 'Category/Extension' CodeGen option, so, I then created a new class called 'Exercise'. From what I have read, this class can contain additional logic such as overriding the prepareForDeletion method. Does this mean I can add the addEntity, updateEntity functions onto this method and then call them from other code files?
My questions are:
Can I implement the same repository pattern that I can use in C#?
I believe this would be on the generated class of my entity (see image below)
Where do I place all my database call functions? If I can use this repository pattern I will place them on there, however, if I cannot, do I place them in a separate code file? Should I place them on the generated entity file which is created for the purposes of adding additional logic?
If I can use the repository pattern, is there a way to get the context injected into this class, or, do I have to call a getContext method each time I want to change it? In C# we can use the services to inject the context into the class each time I want to make changes to the database - I am unsure if the same is possible in Swift.
If I understand correctly, in Swift the equivalent of your 'repository' class could be one of two things. It could be context of core data, which you'd run queries and saves to OR (more likely) you would create a new class or struct that obscured away core data from the business side. Assuming the later, your "dataManager" class would perform all interactions with core data. It could then either return NSmanagedobjects to the business side, or you could map/transform/convert to some other type.
Yes, Exercise is a object that subclasses nsmanagedobject, so it has all the core data features of a managed object, but you can add any custom functions your want.
Your data manager class would perform the queries and return the correct objects. For example data manger.getExercises() -> [Exercises], dataManager.save(_ exercise: Exercise), etc....
You'll need to consider thread safety in your pattern. One option is converting your nsmanagedobjects to struct in your datamanager and not returning nsmangedobjects. Structs are thread safe and using codable you can easily convert between exerciseManagedOjbect and exerciseStruct. Plus, with this dataManager class example, you could remove core data for another persistence option in the future with reduced impact to your app overall.

Do Core Data objects replace standard class objects?

I'm getting into Core Data and have started making "Classes" out of entities. Do I use these classes based off of entities as regular classes with methods etc?
Normally if I was using SQL directly I would have classes for each of my database objects (Tables) that store the working data and perform their functions.
Is this the same with Core Data - do I use the entity-based classes (subclasses of NSManagedObject).
So I might have these entities: Business -> Departments -> Employees
To comply with Core Data - do I make one class for each of these subclassing NSManagedObject and then add methods to it accordingly (like I would an NSObject class)?
Yes, you usually use the Core Data generated classes. You usually don't add methods to those classes, instead you should put them into a Category. This is because if you change an entity, you need to regenerate the class which will erase any methods that you added.
Yes(ish). They are your model classes. You aren't creating them 'out of' entities, they are the code representation of your entities.
You should have one class per entity, but you shouldn't create them yourself. You should get Xcode to create the classes. Or, better yet, use mogenerator.

Working with 2 CoreData objects

I need to have 2 separate data bases on my project, so my question is, how can I have more than 1 CoreData data base on the same project? Im asking this since I already have one coredata data base setup.
I would be very thankful if I could have an explanation or a tutorial/example on how to address this problem.
To create multiple Core Data stores, you make a separate xcdatamodel schema for each of the data stores. In your application, you need to choose how you separate Core Data "stacks" for each of these schemata:
you could have separate NSManagedObjectModel instances, one for each schema; or you could create a merged model that contains the objects from both schemata.
you'll need at least one NSPersistentStore and NSPersistentStoreCoordinator for each managed object model - for most practical uses this means either one per model or a single store if you're using a merged model.
you then create NSManagedObjectContext instances as you need them, backed by the persistent store coordinator(s).
However, this is iOS, so users of your application will probably never manage or care about how your data stores are organised. Unless you have a technical reason not to, you will find things easier just to define all of your entities in a single Core Data model.

How to create Entity dynamically in Objective-C?

I'm building an iPad application where I need user to create entity dynamically. I'm already having 3 entities which program uses.
Could you help me with code how to do it?
I want to understand the whole structure according to my understanding I have to create new managedObjectModel, add new entities and than merge it with existing one, is it correct?
While it is possible to create a new entity and a new model on the fly in practice this is massively complex. If nothing else you would have to migrate any existing persisted data to the new model and a new persistent store file. I strongly recommend against attempting this especially if you are just starting out with Core Data.
You do have options:
Firstly, are you sure you actually need a new entity? People just starting out with Core Data often mistake entities for managed objects. Entities are to managed objects as classes are to instances. Entities are abstractions used to create the object graph. They don't actually contain data. The times when you need new entities are very,very rare.
Secondly, if you do need some kind of dynamic entity, it would usually be best to decompose the dynamic entity into numerous fixed subentities and then use relationships to create a virtual entity. E.g. you need a dynamic Person "entity" so you create several entities in the model each of which holds one attribute of the person. You could have a Field entity which would have a fieldName attribute and then a fieldValue attribute. Then have a an actual Person entity that has no attributes but just relationships to the necessary Field objects. You could add any fields needed to any person and then reconstitute an virtual person object by walking the relationships to its fields.
I rather doubt however that you need that kind of flexibility. Such a need is very rare. I would step back and see exactly what dynamic data you think the user might need to enter.
That's correct -- you'd create an array of NSEntityDescription objects, then call setEntities: on the new managed object model. Then, finally, you'd merge that model with your built-in model.
But note that you can't change a model once it has been used to create a managed object context (or used for storage). You'll need to create new storage and context after the model is changed.

How to group methods belong to one entity in one class file in Core Data like in Entity Framework?

How to group methods belong to one entity in one class file in Core Data like Entity Framework?
In Linq, we can put all methods in the domain object class and reuse them, in Core Data, is there any way to create different classes for different entities? Or we can only use predicate to retrieve?
It seems that I can't define the class for each entity I configured in the data model. And it is not like hibernate that I can control the physical database schema via ORM. Correct me if I am wrong, I don't believe Core Data can do this as far I know.
So what is the advantage to use Core Data? And is there any mechanism on Cocoa that I can define my domain object classes including primary key, foreign key, for instance, and then create the database schema then?
It seems like the Core Data can only support configuring the objects but there is even no way to configure the physical database via the Core Data.
In your Core Data model you can define which class to instantiate your entities as:
alt text http://img404.imageshack.us/img404/3368/setclass.png
When Core Data fetches objects from the store, it will attempt to create them as instances of this class (although it's not quite that simple, Core Data does some tricks).
You can auto-generate class files for your entities by opening your core data model in a new window, and choosing File->New File:
alt text http://img241.imageshack.us/img241/8238/newfile.png
You should see a new "Managed Object Class" item:
alt text http://img46.imageshack.us/img46/348/managedobjectclass.png
Choose this and select the entities to generate classes for:
alt text http://img241.imageshack.us/img241/5030/selectentity.png
A class will be generated with various properties for getting/setting the attributes on your entity:
alt text http://img10.imageshack.us/img10/9868/generatedproperties.png
If you want to add your own methods, I would recommend you add them to a separate Category. This is because you will often want to regenerate these core data classes when you add new properties or change the entities. If you make additions directly to these files you will lose your changes the next time you generate them.
So create a category called Person+Additions or whatever name you think is appropriate:
alt text http://img294.imageshack.us/img294/8871/addcategory.png
And add any new methods or properties to this class:
alt text http://img717.imageshack.us/img717/3884/addmethods.png
Note that you cannot add new instance variables, but NSManagedObject has facilities to get/set values in an internal dictionary. See the NSManagedObject documentation
So once you've done all this, all you do is cast the NSManagedObject you get from a fetch request (or wherever) to the appropriate type:
#import "Person+Additions.h"
//...
Person *p = (Person *) [fetchResult objectAtIndex:0];
[p myCustomMethod];
//...
As for your other questions about primary keys, and interacting with the physical database, this isn't really what Core Data is designed to provide you. You should not think too much about the underlying database, Core Data is meant to be more high level than that. You define your model, and fetch objects through the API. Primary keys and othe "database-y" details like this are not exposed.
If you want full control over the database you should use the sqlite APIs. But I would say for the large majority of applications Core Data is the better choice.
Look at the docs for KVC ("key-value-coding"). You use key paths to obtain the values you want. You can also sort the data in an array using a key path. For that, take a look at NSSortDescriptors. Otherwise, yes, just change your NSPredicate and re-fetch.