How do you manage and use “Many to many” core data relationships?

后端 未结 5 1178
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-12-04 15:55

I\'m creating an app and trying to use core data, because it seems like it\'s the objective-C approved way to create a data storage system. The use case I have involves \"ma

相关标签:
5条回答
  • 2020-12-04 16:24

    If your question is "how you could do that in core data", the answer is exactly as you describe. Create a to-many relationship in each entity, and define each as the inverse of the other.

    If your question is "how could this possibly work", you might find it useful to look at the sqlite database that is created from your model to see how it sets things up. CoreData is pretty good at making it so you shouldn't care about the details, but if you insist on understanding the details there's nothing stopping you from looking at the data to see what it is doing.

    Once you have this in place, you would traverse the relationship as necessary to get the attributes you want. You can do that in code using NSManagedObject instances. For example:

    NSManagedObject *manager = // get a reference to a manager here
    NSSet *employees = [manager valueForKey:@"employees"];
    for (NSManagedObject *employee in employees) {
        NSString *employeeName = [employee valueForKey:@"name"];
        // Do whatever else you want here
    }
    

    This sample can also be simplified using direct property access rather than KVO syntax, but you get the idea.

    If you are looking to traverse this many-to-many relationship more directly as part of a fetch query, then you can do some things with predicates to get what you want. Refer to Apple's predicate programming guide for examples of what you can put in a predicate

    0 讨论(0)
  • 2020-12-04 16:25

    Let's say you have two entities in your database, employees and managers. They would look something like this in the code:

    @interface Employee :  NSManagedObject  
    {
    
    }
    
    @property (nonatomic, retain) NSNumber * id;
    @property (nonatomic, retain) NSSet* managers;
    
    @interface Manager :  NSManagedObject  
    {
    
    }
    
    @property (nonatomic, retain) NSNumber * id;
    @property (nonatomic, retain) NSSet* employees;
    

    So let's say you wanted to retrieve all the employees for manager number 1, you would just have to get the manager object from the database:

    NSNumber *managerID = [NSNumber numberWithInt:1];
    NSEntityDescription * entityDescription = [NSEntityDescription entityForName:@"Manager"                                                       inManagedObjectContext:managedObjectContext]; 
    NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];  
    [request setEntity:entityDescription];  
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K == %d", @"id", managerID];   
    [request setPredicate:predicate];
    NSArray *array = [managedObjectContext executeFetchRequest:request error:&error];
    Manager *manager = [array objectAtIndex:0];
    

    and then you would have all its employees in the employees property:

    NSSet *allHisEmployees = manager.employees;
    

    It would be exactly the same to retrieve the managers for a given employee.

    I hope it clears things up

    0 讨论(0)
  • 2020-12-04 16:25

    Possibly what you are stuck on is how to get from the abstract data model realm to a set of objects that you use in code. If so, look into using mogenerator:

    http://rentzsch.github.com/mogenerator/

    That's a command line utility (not sure how well the XCode integration works these days) where you point it at a model, and it gives you sets of data objects you can use. You need to have an object name set for each entity in addition to the entity name.

    The generated data objects have the calls like employee.managers, which would give you a set of Manager entities for an employee, and vice-versa.

    0 讨论(0)
  • 2020-12-04 16:40

    Peter: "I have nine bosses, Bob." Bob: "Say again?" Peter: "Nine."

    Take your brain out of the database. Do not ask how to access a cross-reference table. Ask how to find the employees for a manager or the managers for an employee.

    If you use a custom subclass of NSManagedObject, you can declare the properties as documented. Then you can simply say:

    NSSet *mgrsEmployees = mgr.employees;
    NSSet *employeesMgrs = employee.managers;
    

    That will not give you all the employees and all the managers, only all the employees for that manager and all the managers for that employee. To change relationships:

    [mgr addEmployeesObject:newEmployee];
    [newEmployee addManagersObject:mgr]; // not necessary, automatic if you define inverse
    
    [mgr removeEmployeesObject:transferredEmployee];
    [transferredEmployee removeManagersObject:mgr]; // not necessary
    [newMgr addEmployeesObject:transferredEmployee];
    [transferredEmployee addManagersObject:newMgr]; // not necessary
    

    You only need to do either one of each pair of statements, and it will implicitly do the other, provided you have defined managers and employees as inverses of each other.

    If you don't use a custom subclass, accessing is a little more verbose

    NSSet *mgrsEmployees = [mgr valueForKey:@"employees"];
    NSSet *employeesMgrs = [employee valueForKey:@"managers"];
    
    NSMutableSet *changeMgrsEmployees = [mgr mutableSetValueForKey:@"employees"];
    [changeMgrsEmployees addObject:newEmployee];
    // not necessary
    NSMutableSet *changeEmployeesMgrs = [employee mutableSetValueForKey:@"managers"];
    [changeEmployeesMgrs addObject:mgr];
    

    Etc.

    0 讨论(0)
  • 2020-12-04 16:45

    The simple answer is to mark the relationship as one to many from both ends when setting up core data in xCode. That in essence creates a many to many. It's in the apple docs somewhere, but I can't find the URL.

    0 讨论(0)
提交回复
热议问题