One-to-Many Relationship: CoreData

我们两清 提交于 2019-12-13 05:04:22

问题


I'm fairly new to coredata and have been stuck on an issue. Any assistance will be greatly appreciated.

Information: I have a core data app with to entities; List and Task. List and Task have a one-to-many relationship.

Task.h

@class List;

@interface Task : NSManagedObject

@property (nonatomic, retain) NSString * task;
@property (nonatomic, retain) NSString * note;
@property (nonatomic, retain) List *list;

@end

List.h

@class Task;

@interface List : NSManagedObject

@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) NSDate * dateCreated;
@property (nonatomic, retain) NSNumber * sortOrder;
@property (nonatomic, retain) NSSet *task;
@end

@interface List (CoreDataGeneratedAccessors)

- (void)addTaskObject:(Task *)value;
- (void)removeTaskObject:(Task *)value;
- (void)addTask:(NSSet *)values;
- (void)removeTask:(NSSet *)values;

@end

I create lists using;

 NSManagedObjectContext *context = [self managedObjectContext];

if ([self.listTextField.text length] == 0) { // Quit here if no text is entered
    [self dismissViewControllerAnimated:YES completion:nil];
    return;
}

// Create a new list.
// Create an NSManagedObject for our database entity.
list = [NSEntityDescription insertNewObjectForEntityForName:@"List" inManagedObjectContext:context];
// Add the new task to the object (which in turns adds to our database).
[list setValue:self.listTextField.text forKey:@"name"];

// Get current date and time.
NSDate *todayDate = [NSDate date];
// Add the date to the object (which in turns adds to our database).
[list setValue:todayDate forKey:@"dateCreated"];


NSError *error = nil;
// Save the object to persistent store
if (![context save:&error]) {
    NSLog(@"Can't Save! %@ %@", error, [error localizedDescription]);
}
[self dismissViewControllerAnimated:YES completion:nil];

I can update already created lists using the code below with cellaccessorybuttontapped;

NSManagedObjectContext *context = [self managedObjectContext];

if ([self.listTextField.text length] == 0) {
    // Delete object from database.
    [context deleteObject:self.list];
    NSError *error = nil;
    // Save the action to persistent store
    if (![context save:&error]) {
        NSLog(@"Can't Save! %@ %@", error, [error localizedDescription]);
    }
    [self dismissViewControllerAnimated:YES completion:nil];
} else {
    // Update existing task.
    [self.list setValue:self.listTextField.text forKey:@"name"];
    // Get current date and time.
    NSDate *todayDate = [NSDate date];
    // Add the date to the object (which in turns adds to our database).
    [list setValue:todayDate forKey:@"dateCreated"];
    NSError *error = nil;
    // Save the action to persistent store
    if (![context save:&error]) {
        NSLog(@"Can't Save! %@ %@", error, [error localizedDescription]);
    }
}
[self dismissViewControllerAnimated:YES completion:nil];

I can then navigate into a list.

My question is how can I then create a task for the list I have just navigated into? It's been 2 days and I've not been able to find anything on Google.


As advised I have added;

@property (strong, nonatomic) List *selectedList;

I now have this as my Save method

NSManagedObjectContext *context = [self managedObjectContext];

// Saving a new task.
Task *task = [NSEntityDescription insertNewObjectForEntityForName:@"Task" inManagedObjectContext:context];

task.task = self.taskText.text;
task.note = self.noteText.text;
task.list = self.selectedList;
NSLog(@"The selected list is: %@", [self.selectedList description]);

NSError *error = nil;
// Save the object to persistent store
if (![context save:&error]) {
    NSLog(@"Can't Save! %@ %@", error, [error localizedDescription]);
}
[self.selectedList addTaskObject:task];
[self dismissViewControllerAnimated:YES completion:nil];

The new task is created but it is created in all lists. Is it possible that this is working and I'm not fetching tasks based on their list?

This is my fetch request when I navigate into a list:

if (fetchedResultsController != nil) {
    return fetchedResultsController;
}

// Create a fetch request.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Create an entity so fetch the data from.
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Task" inManagedObjectContext:self.managedObjectContext];
// Set the entity of the fetch request.
[fetchRequest setEntity:entity];
// Set the amount to be fetched at a time
[fetchRequest setFetchBatchSize:20];
// Create a sort descriptor.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"task" ascending:NO];
// Attach the sort descriptor to the fetch request.
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];

// Create a fetch result controller using the fetch request
NSFetchedResultsController *theFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
                                                                                              managedObjectContext:self.managedObjectContext
                                                                                                sectionNameKeyPath:nil
                                                                                                         cacheName:nil];
self.fetchedResultsController = theFetchedResultsController;
theFetchedResultsController.delegate = self;

// Perform fetch.
NSError *error = nil;
if (![self.fetchedResultsController performFetch:&error]) {
    // Handle error.
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    exit(-1);  // Fail
}
return fetchedResultsController;

回答1:


You need to keep track of the list that you have navigated into. One way of doing it would be to create a property called as parentList like so

@property(nonatomic,strong) List *parentList

in the view controller you create a task in. And just before navigating to the view controller set this property.

In the task view controller you do a insert similar to the List object using Task *reqdTask = [NSEntityDescription insertNewObjectForEntityForName:@"Task" inManagedObjectContext:context]; and then set all the values once say Save button is pressed.

[parentList addTaskObject: reqdTask];

and ur done. This will create a Task in the task entity and map it to the List entity. Hope this helps.

**EDIT***

You need to do this [parentList addTaskObject: reqdTask]; before saving your context.

Add this in the NSFectResultsController
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"list = %@",self.parentList]];

so it will be something like this

// Create a fetch request.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Create an entity so fetch the data from.
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Task" inManagedObjectContext:self.managedObjectContext];
// Set the entity of the fetch request.
[fetchRequest setEntity:entity];
// Set the amount to be fetched at a time
[fetchRequest setFetchBatchSize:20];
// Create a Predicate.
[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"list = %@",self.parentList]];
//continue

this will bring the task associated with the selected list.




回答2:


That is what these methods in your entity header are for:

- (void)addTaskObject:(Task *)value;
- (void)removeTaskObject:(Task *)value;
- (void)addTask:(NSSet *)values;
- (void)removeTask:(NSSet *)values;

You'll create a new task entity:

Task *t = [NSEntityDescription insertNewObjectForEntityForName:@"Task" inManagedObjectContext:context];

Then complete the fields in it as you did with your list object:

t.task = @"Whatever";
t.note = @"Whatever Note";
t.list = currentlySelectedListItem; // whatever that happens to be -- it will be a (List *)something

Then, you want to add the task object to the list:

[currentlySelectedListItem addTask:t];

Then save the context & you're done.

Key thing here is that you're effectively updating the List object by adding a task to the set of Task values contained in the NSSet. And t.list is going to contain a pointer to the parent List object.

Looks to me like you have it laid out just fine (I'm assuming the:

@property (nonatomic, retain) List *list;

Is a relationship to the parent List and not just another value you have defined; that looks to be the case).



来源:https://stackoverflow.com/questions/23947052/one-to-many-relationship-coredata

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!