Reputation: 1110
I'm not sure if my understanding of Core Data relationships is flawed as I can't seem to achieve what I want to do.
I have a 2 entities created to manage Chat on the app and a one-to-Many relationship between the users and the messages. So a user can have many messages but the messages have just you user (creator).
I am trying to update the ChatUser
entity relationship when a new message is added whereby a connection between the ChatUser
ID and the ChatMessage
is established. I can do this but the issue arises when I go to add a new message to an existing userId
. All that is currently being achieved though is adding an extra userId
into ChatUser
instead of adding only the relationship to the existing UserId
.
NSManagedObjectContext *context = [self managedObjectContext];
NSError *error = nil;
// 4 . Get Timestamp for Rippll
float timestamp = @([[NSDate date] timeIntervalSince1970]).floatValue;
NSString * jayID = @"eu-west-1:be6457ce-bac1-412d-9307-e375e52e22ff";
NSString *message = @"Science string!";
// Create a new managed object
ChatUser *chatUserManagedObject = [NSEntityDescription insertNewObjectForEntityForName:@"ChatUser" inManagedObjectContext:context];
Chat *chatManagedObject = [NSEntityDescription insertNewObjectForEntityForName:@"ChatMessage" inManagedObjectContext:context];
Timeline *timelineManagedObject = [NSEntityDescription insertNewObjectForEntityForName:@"Timeline" inManagedObjectContext:context];
// 3 . Save Timeline
[timelineManagedObject setEvent:chatEvent];
[timelineManagedObject setTimestamp:[NSNumber numberWithFloat:timestamp]];
[timelineManagedObject setMeta:@""];
[timelineManagedObject setViewed:@NO];
[timelineManagedObject setEventID:jayID];
//Save UserMessage
[chatManagedObject setChatId:jayID];
[chatManagedObject setTimestamp:[NSNumber numberWithFloat:timestamp]];
[chatManagedObject setMessage:message];
[chatManagedObject setMedia:@""];
//Check if value exists
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"ChatUser"];
[request setPredicate:[NSPredicate predicateWithFormat:@"userId = %@", jayID]];
[request setFetchLimit:1];
NSArray *entities = [[context executeFetchRequest:request error:&error] mutableCopy];
if (entities.count == 0) {
NSLog(@"GOOD TO ADD");
// no matching object
[chatUserManagedObject setUserId:jayID];
//Create Relationship
[chatUserManagedObject addChatObject:chatManagedObject];
} else {
NSLog(@"IT EXISTS!");
[chatManagedObject setChat:chatUserManagedObject];
}
// Save the object to persistent store
if (![context save:&error]) {
NSLog(@"Can't Save! %@ %@", error, [error localizedDescription]);
}
Upvotes: 15
Views: 2283
Reputation: 974
Try to implement something like this one. This solution is almost the same as proposed by Amin Negm-Awad
NSManagedObjectContext *context = [self managedObjectContext];
NSError *error = nil;
// 4 . Get Timestamp for Rippll
NSString * jayID = @"eu-west-1:be6457ce-bac1-412d-9307-e375e52e22ff";
NSString *message = @"Science string!";
//Check if value exists
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"ChatUser"];
[request setPredicate:[NSPredicate predicateWithFormat:@"userId = %@", jayID]];
[request setFetchLimit:1];
NSArray *entities = [[context executeFetchRequest:request error:&error] mutableCopy];
ChatUser *chatUserManagedObject = nil;
if (entities.count)
{
NSLog(@"IT EXISTS!");
chatUserManagedObject = entities.firstObject;
}
else
{
NSLog(@"GOOD TO ADD");
chatUserManagedObject = [NSEntityDescription insertNewObjectForEntityForName:@"ChatUser" inManagedObjectContext:context];
[chatUserManagedObject setUserId:jayID];
}
// Create a new managed object
Chat *chatManagedObject = [NSEntityDescription insertNewObjectForEntityForName:@"ChatMessage" inManagedObjectContext:context];
//Save UserMessage
[chatManagedObject setChatId:jayID];
[chatManagedObject setTimestamp:[NSDate date]];
[chatManagedObject setMessage:message];
[chatManagedObject setMedia:@""];
[chatUserManagedObject addChatObject:chatManagedObject];
// Save the object to persistent store
if (![context save:&error]) {
NSLog(@"Can't Save! %@ %@", error, [error localizedDescription]);
}
Upvotes: 1
Reputation: 7416
Core Data will automatically manage the other end of the relationship once you initiate it from either direction. You can either add to ChatUser
's chat
collection or set ChatMessage
's chat
with an instance of an NSManagedObject
and that's all you have to do. Note that this process does not require you to manage foreign keys, that complexity is abstracted from you. You can still store server-side IDs if they help you interact with an API, but they are not required for Core Data.
I would recommend changing one end of the relationship so that both are not named the same thing. Consider updating ChatUser
's relationship to be messages
or something similar.
Upvotes: 6
Reputation: 16660
I thin k, @PangHoMing was on the right track, but used Magical Records. Let's do it solely with CD:
First rename the relationships. Probably in ChatMessage
there should be a to-1 relationship named user
(or chatUser
) and in ChatUser
there should be a to-N relationship messages
(or chatMessages
). They should be inverse relationship.
Next you should ask for the existence of a user before creating it. (Otherwise you create phantom users.) You got the code for it:
// Create message as you did
ChatMessage *message = …;
…
// The user will go here
ChatUser *user; // Do not use types in names unless conversion is subject of your code
// Look for an existing one
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"ChatUser"];
[request setPredicate:[NSPredicate predicateWithFormat:@"userId = %@", jayID]];
[request setFetchLimit:1];
NSArray *entities = [[context executeFetchRequest:request error:&error] mutableCopy];
if (entities.count == 0)
{
// Only if there is none, create one
user = [NSEntityDescription insertNewObjectForEntityForName:@"ChatUser" inManagedObjectContext:context];
// Set-up user's properties
…
}
else
{
// Use the existing one
user = entities[0];
}
[message setValue:user forKey:@"user"]; // message.user = user;
As mentioned by others, the inverse relationship is maintained by CD. However, you can use the inverse relationship to add the message, if this is more readable for you:
[[user mutableSetValueForKey:@"messages"] addObject:message]; // [user addMessagesObject:message]
This will maintain the "original" relationship, too.
Upvotes: 3
Reputation: 1319
Feel free to ask any follow up question if you have any. Cheers!
Upvotes: 1