Relational database in Realm? - ios

I want to create simple relational database in the iOS Realm DB. How can i link user id and there Wishlist product similar to the relational database in SQL. Example like bellow image :
I know i can create 2 separate Realm models (tables) to store user id with time_stamp and in second table for Wishlist where there are user id with each Wishlist products or user id and a Wishlist, where the user has an array of Wishlist. Now i want to store all users with there multiple wishlists. This means that every time the user enters in APP, I have to query every wishlists in existence to see whether its intended for this specific wishlists. The problem is in Wishlist table, it doesn't have any primary key and realm not allowing to create model without primary key.
Does Realm support foreign key concept ? and use of composite key is quit complicated. Is there a more efficient way to do this?

You can use RLMArray , where RLMArray is the container type in Realm used to define to-many relationships.
As mentioned in the official Realm documentation for objective c check example here.
Also go through this link it might help RLMArray doc

RLMArray is used for the relational database concept in realm. You can try like this:
#import <Realm/Realm.h>
#class User;
// User model
#interface User : RLMObject
#property NSString *name;
#property NSString *user_id;
#property RLMArray<Watchlist *><Watchlist> *watchlist;
#end
RLM_ARRAY_TYPE(Dog) // define RLMArray<Dog>
// Watchlist model
#interface Watchlist : RLMObject
#property NSString *id;
#property NSInteger *activity;
#property NSInteger *cost;
#end
RLM_ARRAY_TYPE(Watchlist) // define RLMArray<Person>
// Implementations
#implementation User
#end // none needed
#implementation Watchlist
#end // none needed
Read data from realm :
RLMResults *watchlistDB = [Watchlist allObjects];
WatchlistDB = [realm_data objectAtIndex:index];
RLMArray *realm_array = WatchlistDB.watchlist;

Related

IOS/Objective-C/Core-Data: Does new Core Data object come with relationship objects?

I am importing book records from JSON into NSManagedobjects that have their own attributes but also relationships to other entities, authors and publishers.
For each book item that comes down from the cloud via JSON, I create a new bookFromServer object. I store the attributes from JSON into this object. This is simple enough with title, bookid etc.
However, the JSON also contains other information that properly belongs in other entities, ie publisher publisher name, publisher address, author first name author last name, author date of birth etc.
My question, is whether I also have access to "phantom" or uninstantiated managedobjects of the entitites with which my object has a relationship? Or do I need to create properties in the object file for each and every attribute.
Here is the NSObject file for BookFromServer
#import <CoreData/CoreData.h>
#class Books;
#class Authors;
#class Publishers;
#interface BookFromServer : NSObject
#property (nonatomic, retain) NSNumber * bid;
#property (nonatomic, retain) NSString * title;
#property (nonatomic, retain) NSNumber * authorid;
#property (nonatomic, retain) NSNumber * publisherid;
//this is relationship
#property (nonatomic, retain) Authors *author;
//this is relationship
#property (nonatomic, retain) Publishers *publisher;
#end
I would like to store author info in something like author.firstname, not as a separate authorfirstname property in books. So my question is when I instantiate a book object, do I get the use of the attributes in the objects available through the relationships?
My question, is whether I also have access to "phantom" or uninstantiated managedobjects of the entitites with which my object has a relationship? Or do I need to create properties in the object file for each and every attribute.
It's exactly the same as with any other kind of object. Using Core Data doesn't change anything here.
New objects are only created when your code creates them. Core Data never creates a new object implicitly or automatically. So if your managed object has relationships to other managed objects, you need to create the managed objects and then update the objects so that their relationships refer to each other.
Properties of managed objects are available when the object is created, so a string or numeric property exists as soon as the managed object exists.

How do I map relationships in Custom NSManagedObject class

I have two entities: Farmer, Livestock. a farmer has a one-to-many relationship with livestocks. So that each farmer may have a name, address, userid, pig set, chicken set, cow set.
I need to create a custom managed object class for farmer as
#interface ManagedFarmer : NSManagedObject
#property (nonatomic, strong) NSString *name;
#property (nonatomic, strong) NSDate *date;
#property (nonatomic, strong) NSString *address;
#property (nonatomic, strong) NSNumber *userid;
#property (nonatomic, strong) NSArray *cows;//? set of cows: relationship to Livestock entity, designated cows
#property (nonatomic, strong) NSArray *chickens;//? 1-to-many relationship to Livestock entity, designated as chickens:
#property (nonatomic, strong) NSArray *pigs;
is NSArray the correct way to represent the relationship data?
when I fetch a farmer by userid, does cascading automatically occur such that I also get all the Livestock entities belonging to this farmer for free?
So a NSManagedObject is used in conjunction with Core Data. Create your model, create the relationships in that model and then have Xcode create your NSManagedObject classes for you.
"NSArray the correct way to represent the relationship data?"
NSSet is used to model relationships in an NSManagedObject subclass. NSArray is used for fetched properties, which are a kind of weak relationship.
Typically you would use the Core Data Model Editor built into Xcode to modify your model, and then have Xcode generate the NSManagedObject subclass files as a template for you to work with. This would automatically generate NSSet properties for relationships (but, sadly, will not automatically generate properties for fetched properties ).
"when I fetch a farmer by userid, does cascading automatically occur such that I also get all the Livestock entities belonging to this farmer for free?"
When objects are fetched their relationships are "faults". The object graph will only have placeholders for the objects at the target of the relationship until they are accessed. This helps limit the size of the in-memory object graph, and is something that Core Data is very good at. You can choose to include the targets of relationships in a fetch by setting the appropriate relationship key paths for fetching on your fetch request using setRelationshipKeyPathsForPrefetching:.
The following link has a basic tutorial for doing what you are asking: http://code.tutsplus.com/tutorials/core-data-from-scratch-subclassing-nsmanagedobject--cms-21880

Parse - Using relations versus pointers?

I am using Parse as my backend. I have problems setting up the correct relation between objects.
I basically have a class named Post, each post belongs to a user(PFUser), and when fetching a post I want the user info to be fetched along with the post.
#interface Post : PFObject<PFSubclassing>
#property (nonatomic, strong) NSDate *time;
#property (nonatomic, strong) NSString *title;
#property (nonatomic, strong) NSString *body;
#property (nonatomic, strong, readonly) PFRelation *user;
// User in backed is defined as a relationship to _user
#end
// Saving the post
[post.user addObject:[PFUser currentUser];
[post saveInBackground];
This works fine and relates the post to that user, but when I try to fetch the post later, it doesn't seem like I can get an instance of _user from PFRelation.
What is the correct way to handle this?
Tried to change PFRelation to PFUser but that would crash because it tries to call save on the PFUser object
A Relation is for when you want a long list of related classes, where an array doesn't work, or when you want to query the related objects as needed and not have the list included every time you load the containing object.
Basically you have 4 options with Parse:
Pointer - single reference to another class (1 to 0..1)
Array - collection of pointers, loaded with the object every time (1 to 0..n, small lists)
Relation - collection of pointers, like a join table in SQL (handled under the covers for you), you must run a query against it to load values (1 to 0..n)
Custom join class - really just another object (like many-to-many join in SQL) with a Pointer to each side plus any related information (1..n to 1..n)
In your case a simple Pointer would do what you want.
In your usecase, a pointer is preferable over a PFRelation. You can include the user info by adding includeKey in your query:
[query includeKey:#"user"];
A way to get a comment count on your post is to add every new comment to an array of pointers in your Post.
It is easy to get stuck in the old SQLish ways when you start using NoSQL databases. If a counter is desirable, you could add a cloud code afterSave function on the comment object that updates the "comments" column of the Post class by adding a pointer to the saved comment to the "comments" array in Post. This way, when you fetch a post you can also use
[query includeKey:#"comments"];
which will give you the Post AND all the comments in one query. If you only need the count, you ommit the includeKey, but you still have an array in "comments" with the pointers, so the comment count is the length of the array.
You must create a query from the PFRelation object, like in this code snippet (taken from Parse documentation) and do an explicit query to retrieve the referenced object:
[[relation query] findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error) {
// There was an error
} else {
// user(s)
}
}];
Parse provides the possibility to retrieve also referenced objects in the original query, and this is done using the "includeKey:" method in the original query (that is the query you setup to get the posts), by asking to return the user data and not just the reference. But I'm not sure if it works for PFRelation as in the documentation it is stated that includeKey works for PFObject and PFRelation is not a PFObject. You may try this code in any case and see if it works or not:
[query includeKey:#"user"]
Create A PFSubClass like
yourClassName:PFObject with PFSubclassing
and then in the header file create a Pointer relation
#property(nonatomic, strong) PFUser *userLikeRelation;
add in m file add
+ (NSString *)parseClassName {
return #"parseTableName";
}
+ (void)load {
[self registerSubclass];
}
finally in the View Controller set relation in query when you are save data in parse.
yourClassName *yourClassNameObj = [yourClassName objectWithClassName:[yourClassName parseClassName]];
[yourClassName setUserCommentRelation:[PFUser currentUser]];
for fetching data you can get data with include key
[yourClassNameObj includeKey:#"NameofRelation"];

iOS Should I Use Core Data? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
I have an exercise application that allows you to create a Workout Program, and then create individual Workouts associated with the Program. You can also create Workouts independent of any Program. I'm new to Obj-C fundamentals and am trying to figure out how I should tie in Workouts with their Program (keeping in mind that eventually reporting data will use the relationship between the two).
I've concluded that this can/should be done in 1 of 2 ways and need help learning which is the most efficient:
1) When a Workout is created, see if it originates from a Program or is on it's own (this is how I've done it successfully now). If it's from a program, add a 'WorkoutInProgram' Core Data attribute to the Workout which will store the ProgramName. Then whenever I want to fetch all Workouts in a Program, I just look up the attribute where WorkoutInProgram == ProgramName.
2) Create some sort of Core Data relationship between Workouts and Programs. When a Workout is created within a Program, the relationship between the ProgramName attribute (of the Program entity) and the Workout entity is stored. I spent around an hour trying to figure out this relationship, got confused, and resorted to #1 which worked.
I'm not sure if a Core Data relationship is useful here, I got hung up on the fact that multiple Workouts would be associated with a single Program entity based on ProgramName.
As always, thank you.
Here is roughly what things should look like in XCode. Program.workouts is a To-Many relationship and Workouts.program is an optional To-One relationship.
Generated NSManagedObject subclasses should look like this
//
// Program.h
// CoreDataLibraryApp
//
//
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#class Workout;
#interface Program : NSManagedObject
#property (nonatomic, retain) NSDate * timeStamp;
#property (nonatomic, retain) NSString * name;
#property (nonatomic, retain) NSSet *workouts;
#end
#interface Program (CoreDataGeneratedAccessors)
- (void)addWorkoutsObject:(Workout *)value;
- (void)removeWorkoutsObject:(Workout *)value;
- (void)addWorkouts:(NSSet *)values;
- (void)removeWorkouts:(NSSet *)values;
#end
//
// Workout.h
// CoreDataLibraryApp
//
//
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#class Program;
#interface Workout : NSManagedObject
#property (nonatomic, retain) NSString * name;
#property (nonatomic, retain) Program *program;
#end
When you create a new Workout you can set the program attribute like this:
newWorkout.program = selectedProgram;
If you want to get all workouts for a program you do something like this
for (Workout *workout in selectedProgram.workouts) {
NSLog(#" workout is %#", workout.name);
}
What you've done so far is create your own relationship manually, you just aren't using Core Data to manage the relationship. I would recommend creating a one-to-many relationship between Program and Workout. The relationship can be specified as optional so it doesn't have to be populated.
Some benefits to having the relationship specified with Core Data include automatically keeping things in sync if the name of the Program ever changes, being able to specify delete behaviors, and code simplification when it comes to fetching the Program associated with a Workout.
One thing that might be causing confusion (I know it did for me at first) is that you don't specify the relationships based on specific attributes (like you would if you were creating a model in a relational DB). You don't, for example, create a specific attribute for the purpose of linking the two entities together. Instead, when you create your relationship, you might name it "program" in the Workout entity and "workouts" in the Program entity.

restkit - having trouble mapping relationships... or something

Setup - using RestKit, along with it's abilities to store data in a CoreData store.
I'm trying to perform two separate GET operations:
issue/:issueId ==> this returns an Issue object, assuming one with that ID exists.
issue/:issueId/comment ==> this returns Comment objects, belonging to the issue matching issueId.
So, for the first call, that just gets an issue back. It will only return comments back if I pass in an extra parameter on the URL. Otherwise, it won't. Of course, if I do ask for it, then the objects get created just fine, and all the objects are connected correctly in my core-data store.
The objects that I'm mapping look like this:
#interface Issue : NSManagedObject
#property (nonatomic) int32_t issueId;
#property (nonatomic, retain) NSSet* comments;
// many other fields not shown.
#end
#interface Comment: NSManagedObject
#property (nonatomic) int32_t commentId;
// many other fields not shown.
#end
Issue has a collection of Comments. Comments don't know about their owning Issue.
So, all I'm trying to do is make it possible for both of these calls to exist.
For example, in our URLs, say "issueId" is 12345. So, if I make one call to http://example.com/issue/12345, I'd like the data to be written to my CoreData store. (This works great, btw). What I would like to happen next is to call "http://example.com/issue/12345/comments", and then have those comments write to the CoreData store, and also be connected to issue-12345, that's already there. That's the part that I'm having trouble with.
If anyone could offer guidance on this, I'd really appreciate it.
After reading this issue on the official repo, I would proceed like follows.
In you Core Data model add the inverse relationship Comment -> Issue, so that your Comment interface looks like
#interface Comment: NSManagedObject
#property (nonatomic, retain) Issue * issue;
#property (nonatomic) int32_t commentId;
// many other fields not shown.
#end
and make that relationship mandatory.
Now you have to setup your mapping adding that relationship, for instance
[issueMapping addRelationshipMappingWithSourceKeyPath:#"comments"
mapping:[self commentMapping]];
If my understanding is correct, RestKit should populate both relationships (the one-to-many Issue -> Comment and its inverse) for you.

Resources