Objective c - Suggested process to prefill complex DB - objective-c

i would like to have some clarification about the correct approach to prefill a (complex) DB with multiple entities.
This is the approach i want to use:
Creation of a separate project that cares about DB Population
In case of Entities with no relations: parsing of a .json file in order to gather information of the Entity
In case of Entities with relation with other Entities (1:N relation):
I have a .json file for each entity
I allocate a Managed Object for each element involved with the relation between the Entities and i fill their attributes.
Please consider the example below for better explaination:
Let's consider the DB contains two Entities: Owner and House with a (1:N) relation.
In order to prefill the DB I:
configurea owner.json file and a house.json file
parse owner.json and gather and create a ManagedOwnerObject
parse house.json and create a set of ManagedHouseObject that have a relation with the first object created.
fill the attribute of ManagedOwnerObject that describe the relation with ManagedHouseObject with the NSSet just created
Iterate the process for all the house.json
Now, this process seems to me a little complex considering that my application has something like 10 Entities connected with 1:N relation.
Could you please suggest me if i'm doing right or if other better solutions could be considered?
Kind regards
Nicolò

You could simply fill the database manually using your app and ship the resulting SQLite file with your app instead of creating an empty one when the user opens the app for the first time.
EDIT:
Using KVC could simplify the creation of the objects. Setting the relationships probably isn't that easy. I would go through all of the data twice. Create the object without relationships in the first run and set up the relationships in the second.
Here is a method to do something similar, without relationships though:
-(void)createEntities:(NSString *)entityName fromFile:(NSString *)filePath inManagedObjectContext:(NSManagedObjectContext *)managedObjectContext {
// Remove all existing objects of this entity.
[self removeExistingEntriesForEntityName:entityName managedObjectContext:managedObjectContext];
// Read all data from file path.
NSArray *newObjects = [self readTestDataFromFilePath:filePath];
// Insert new object for all existing keys.
for (NSDictionary *no in newObjects) {
NSManagedObject *managedObject = [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:managedObjectContext];
for (NSString *key in no.keyEnumerator) {
[managedObject setValue:[no valueForKey:key] forKeyPath:key];
}
}
[(AppDelegate *)[[UIApplication sharedApplication] delegate] saveContext];
}

Related

Objective C - JSON to CoreData with category relation [duplicate]

I'm a nwebie in Core Data, i have designed a navigation based application and some of the data i use are created on run time(come from a URL via JSON). I took a few tutorials an searched for almost a day but haven't still realized how to save the incoming JSON data to the Entity (or event?) in my Core Data model. I fetch the data in the DetailViewController class and i need to save this data to Core Data(I have prepared an Entity with 7 properties). Can anyone please help?(If you know a good tutorial or sample code i will be pleased)
EDIT This may be a little specific but i really have trouble with and need just a little help.
My data comes to the app from a kind of restful server(i wrote it in PHP), firstly user enters his/her login informations(which i have saved to the database on server before) and when the response data comes i will use different elements of it in differen views(for example the user_id will be used on a view and the buttonData etc on other views). My question is, how will i save JSON data into my core data model(has tree Entities for the moment). Thanks in advance
Note: I lokked arround a lot but couldn't find any answer&tutorial about an app like mine
The best way to do that would be to create entities corresponding to JSON structure. Easiest was is when each JSON object becomes an entity, and arrays become arrays of entities. Be reasonable, however, and don't introduce too much overkill for JSON subobjects that are essentially part of its superobject.
When you have created entities, you can start off with the parsing and translation. Use some JSON framework (starting from iOS5 there's one from Apple) and parse JSON string into object tree, where root item is either an NSArray or NSDictionary, and subelements will be NSArray, NSDictionary, NSNumber, NSString or NSNull.
Go over them one by one in iterational loops and assign according values to your core data entity attributes. You can make use of NSKeyValueCoding here and avoid too much manual mapping of the attribute names. If your JSON attributes are of the same name as entity attributes, you'll be able to just go over all dictionary elements and parse them into attributes of the same name.
Example
My parsing code in the similar situation was as follows:
NSDictionary *parsedFeed = /* your way to get a dictionary */;
for (NSString *key in parsedFeed) {
id value = [parsedFeed objectForKey:key];
// Don't assign NSNull, it will break assignments to NSString, etc.
if (value && [value isKindOfClass:[NSNull class]])
value = nil;
#try {
[yourCreatedEntity setValue:value forKey:property];
} #catch (NSException *exception) {
// Exception means such attribute is not defined in the class or some other error.
}
}
This code will work in trivial situation, however, it may need to be expanded, depending on your needs:
With some kinds of custom mappings in case you want your JSON value be placed in differently named attribute.
If your JSON has sub-objects or arrays of sub-objects, you will need to detect those cases, for example in setters, and initiate new parsing one level deeper. Otherwise with my example you will face the situation that assigns NSDictionary object to an NSManagedObject.
I don't think it is reasonable to dive into these, more advanced matters in scope of this answer, as it will expand it too much.
I suggest you to use this library : https://github.com/TouchCode/TouchJSON
And then if you want to make a factory to parse json and feed your code data, you can use selectors to call methods to fill all your attributes.
Chances are your JSON data gets converted to an NSDictionary or NSArray (or some combination of the two). Simply extract the key/values from the JSON structure and add them to your entity class.
This lib helps me lot
Features
Attribute and relationship mapping to JSON key paths.
Value transformation using named NSValueTransformer objects.
Object graph preservation.
Support for entity inheritance
Works vice-versa

NSFetchedResultsController add Objects manually

I recently stumbled across a difficult problem..
I'm normally using a NSFetchedResultsController to get Data out of my CoreData, and display it within a TableViewController.
The problem I have now is that I can't get the results I want with a NSFetchRequest right away, because having a m:n relationship and I implemented a Table in Core Data (References) which stores the references to the Objects...
So what I do now is, I use a fetch Request:
NSArray* references = [self.context executeFetchRequest:fetchRequest error:&error];
and then iterate through this array to get my Objects:
for(References* ref in references)
{
Post* tmp = ref.ref_of_post;
}
So is there a way to manually add these objects to my NSFetchedResultsController or is there a possibility to get the wanted object trough a NSFetchRequest?
Thanks for your help.
Never mind that.
I just added these Objects to a NSMutableArray and then would use this Array in the same way as the NSFetchedResultsController..

Create a relationship between two entities in Core Data

I have a simple has many relationship between 2 entities in Core Data:
Team <------->> Games
When I insert a new game managed object into a context, I need to query some properties of the team entity, at the model layer. However, when I use awakeFromInsert the relationship has not been set yet, so team is nil.
// game.m
- awakeFromInsert
{
[super awakeFromInsert];
if ([self team] isActive] {
//.... set game properties
}
}
Is there a way to build the relationship before calling insert and setting the relationship after:
Game *newGame = [NSEntityDescription insertNewObjectForEntityForName:#"Game"
inManagedObjectContext:managedObjectContext];
[newGame setTeam:team];
In rails I would use #team.games.build but this doesn't seem possible in Core Data.
I suspect you will either need a custom method such as + (Game *)insertGameForTeam:(Team *)team and do your team checks there or else handle the relationship conditions in - (void)willSave if you need to keep it at the model level.
Using only the default logic, the object doesn't exist until you finish inserting it and you can't associate it with another object until it exists.

How to access CoreData entities based on a to-many relationship of another entity?

I am learning CoreData with a sample inventory app. My Data Model has 2 entities, "Possession" and "Asset Type". Possessions have a to-one relationship to Asset Types called "assetType" and Asset Types have a to-many relationship to Possessions named "possessions". Each Possession has only one Asset Type, but Asset Types have many Possessions.
I'd like to sort a tableview into sections based on asset types. I need some help populating my data structure for this though.
Here is how I'll model my table view controller
NSArray for table sections
each section object in the array will be an NSDictionary with 2 keys, #"Header" - which will be the Asset Type, and #"Possessions" which is an array of possessions of that asset type.
I can handle building my table view from this structure no problem. I can also handle fetching the Asset Types from CoreData into the header key of my dictionary. Where I am stumped is how do I take advantage of the to-many relationship that asset types have to possessions so I can get the possessions into an array for the dictionary.
How do I get each Asset Type's possessions into an array?
Do I need to make a fetch request with a predicate to fetch possessions that have the matching asset type, or is there a simpler way? - Seems that would be inefficient as it would have to check all possessions for a match!?!?!?!?
Is the to-many relationship "possessions" of AssetType entity an accessible property of the AssetType entity? If so how do I access it? What does it return?
I am not looking for free code, but I am willing to post mine if needed. What I'd really like is to know the best way to solve this problem and maybe pointed to helpful info online to accomplish this. I am not a complete newb, but I am still having trouble wrapping my head around CoreData and thus far the Apple docs are still pretty confusing to me on this subject. I am appreciative for any help offered.
If you've created your AssetType class with Xcode default NSManagedObject template (see image)
you should have something like that in your AssetType.h:
#interface AssetType : NSManagedObject
#property (nonatomic, retain) NSSet *possessions;
#end
#interface AssetType (CoreDataGeneratedAccessors)
- (void) addPossessionsObject: (Possession *) value;
- (void) removePossessionsObject: (Possession *) value;
- (void) addPossessions: (NSSet *) value;
- (void) removePossessions: (NSSet *) value
#end
So if you have an AssetType object, you can access all Possession objects related to it via the possessions property. It is not ordered by default though, so to access these objects as an array, you will need to call the -allObjects method of the set which returns the objects within the set as an array and then probably sort these objects somehow.
Edit:
Also, even if you did not create the NSManagedObject subclass that way and it does not have the possessions property implemented yet, you could add this property to the class in the just same way as stated in the example above and implement it within the AssetType.m as #dynamic possessions.
from what I'm reading I suspect this is much easier than you might think.
It sounds to me like you have envisaged using a dictionary data structure with for use in your UITableController's tableView:cellForRowAtIndexPath: method, when you probably don't need to use one at all.
When you Table view controller instantiates, (viewDidLoad: is probably the most appropriate place) simply retrieve your assets with code like this:
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Asset" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSError *error = nil;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
if (fetchedObjects == nil) {
// handle errors here
}
[fetchRequest release];
If necessary assign the fetchedObjects array to an instance variable of type NSArray so you can refer to it in multiple places in the UITableViewController class managing the table. Then after the above code you can do something like this:
self.assets = fetchedObjects;
If you have not created a custom subclass for your asset NSManagedObject, then each object in the array will be of type NSManagedObject and you will need to read it into a variable of that type.
When you need to the list of possessions related to an asset, it's already there in each asset object in your array (that's the beauty of CoreData, if it's not actually instantiated in memory, the moment you try to access the property, CoreData will automagically instantiate it for you).
So let's say you have not defined a custom class for your NSManagedObject then your array objects will be of that type. Assign one of the asset objects in your array to a local variable named (appropriately) asset,
For example, this will assign the object at index 0 to a local variable.
NSManagedObject *asset = [self.assets objectAtIndex:0];
You get can get your set of possessions with the code:
NSSet *assetPossessions = [asset valueForKey:"#possessions"];
(presuming the relationship defined in the model editor in xCode has been named "possessions")
Alternatively If you generated your own custom subclass for the Asset NSManagedObject, then, this might be a better example:
MyManagedAssetObject *asset = [self.assets objectAtIndex:0];
NSSet *assetPossessions = asset.possessions;
Note in this example, I have presumed you are not using a NSFetchedResultsController. It is actually even easier to manage a table using one, however as is often the case with programming it is easier only once you know that "just one more thing" and so (paradoxically) complicates the answer. Since you didn't mention it, I have assumed you are not using it.
Hope this helps. Paul

How can i save JSON objects to Core Data?

I'm a nwebie in Core Data, i have designed a navigation based application and some of the data i use are created on run time(come from a URL via JSON). I took a few tutorials an searched for almost a day but haven't still realized how to save the incoming JSON data to the Entity (or event?) in my Core Data model. I fetch the data in the DetailViewController class and i need to save this data to Core Data(I have prepared an Entity with 7 properties). Can anyone please help?(If you know a good tutorial or sample code i will be pleased)
EDIT This may be a little specific but i really have trouble with and need just a little help.
My data comes to the app from a kind of restful server(i wrote it in PHP), firstly user enters his/her login informations(which i have saved to the database on server before) and when the response data comes i will use different elements of it in differen views(for example the user_id will be used on a view and the buttonData etc on other views). My question is, how will i save JSON data into my core data model(has tree Entities for the moment). Thanks in advance
Note: I lokked arround a lot but couldn't find any answer&tutorial about an app like mine
The best way to do that would be to create entities corresponding to JSON structure. Easiest was is when each JSON object becomes an entity, and arrays become arrays of entities. Be reasonable, however, and don't introduce too much overkill for JSON subobjects that are essentially part of its superobject.
When you have created entities, you can start off with the parsing and translation. Use some JSON framework (starting from iOS5 there's one from Apple) and parse JSON string into object tree, where root item is either an NSArray or NSDictionary, and subelements will be NSArray, NSDictionary, NSNumber, NSString or NSNull.
Go over them one by one in iterational loops and assign according values to your core data entity attributes. You can make use of NSKeyValueCoding here and avoid too much manual mapping of the attribute names. If your JSON attributes are of the same name as entity attributes, you'll be able to just go over all dictionary elements and parse them into attributes of the same name.
Example
My parsing code in the similar situation was as follows:
NSDictionary *parsedFeed = /* your way to get a dictionary */;
for (NSString *key in parsedFeed) {
id value = [parsedFeed objectForKey:key];
// Don't assign NSNull, it will break assignments to NSString, etc.
if (value && [value isKindOfClass:[NSNull class]])
value = nil;
#try {
[yourCreatedEntity setValue:value forKey:property];
} #catch (NSException *exception) {
// Exception means such attribute is not defined in the class or some other error.
}
}
This code will work in trivial situation, however, it may need to be expanded, depending on your needs:
With some kinds of custom mappings in case you want your JSON value be placed in differently named attribute.
If your JSON has sub-objects or arrays of sub-objects, you will need to detect those cases, for example in setters, and initiate new parsing one level deeper. Otherwise with my example you will face the situation that assigns NSDictionary object to an NSManagedObject.
I don't think it is reasonable to dive into these, more advanced matters in scope of this answer, as it will expand it too much.
I suggest you to use this library : https://github.com/TouchCode/TouchJSON
And then if you want to make a factory to parse json and feed your code data, you can use selectors to call methods to fill all your attributes.
Chances are your JSON data gets converted to an NSDictionary or NSArray (or some combination of the two). Simply extract the key/values from the JSON structure and add them to your entity class.
This lib helps me lot
Features
Attribute and relationship mapping to JSON key paths.
Value transformation using named NSValueTransformer objects.
Object graph preservation.
Support for entity inheritance
Works vice-versa