2011-09-27 25 views
18

Estoy creando una aplicación e intentando usar datos básicos, porque parece que es la manera aprobada por C para crear un sistema de almacenamiento de datos. El caso de uso que tengo involucra relaciones de "muchos a muchos", como normalmente verías en un sistema SQL estándar. Entiendo que el objetivo C no es una base de datos y funciona de manera diferente. También he revisado la documentación aquí:¿Cómo gestionas y utilizas las relaciones de datos centrales "Muchos a muchos"?

http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/CoreData/Articles/cdRelationships.html#//apple_ref/doc/uid/TP40001857-SW10

y varios otros lugares. Y aún así, sigo teniendo problemas. ¿Puede alguien explicarme qué haría si tuviera un caso de uso en el que necesitaría usar una tabla de referencia cruzada de SQL? Por ejemplo:

Administradores | Empleados

El administrador puede tener varios empleados, pero los empleados también pueden tener varios administradores. En SQL, crearía una tabla de referencia cruzada y luego usaría eso.

Ejemplo: http://www.tomjewett.com/dbdesign/dbdesign.php?page=manymany.php

Puede alguien explicar cómo se puede hacer eso en los datos básicos?

De acuerdo con la documentación de datos central, que dicen lo siguiente:

"se define un muchos-a-muchos relación utilizando dos relaciones a muchos La primera relación a muchos va desde la primera entidad a la segunda. Entidad La segunda relación entre muchos va desde la segunda entidad a la primera entidad. Luego establece que cada uno sea el inverso del otro. (Si tiene antecedentes en la administración de bases de datos y esto le causa preocupación, no se preocupe: si utiliza una tienda SQLite, Core Data crea automáticamente la tabla de combinación intermedia para usted). "

Pero, además de" no estar preocupado ", no sé cómo podría funcionar esto.

+0

Es éste un duplicado de http://stackoverflow.com/questions/1449523/need -help-with-many-to-many-relationships-in-core-data-for-iphone? –

+0

No, porque ese tipo hace referencia a una tabla de unión. Por lo que he leído en los documentos, ¿no necesitas crear una tabla de unión? Además, creo que está pidiendo que se busquen datos. – Darkenor

Respuesta

50

Pedro: "Tengo nueve jefes, Bob." Bob: "¿Decir de nuevo?" Peter: "Nueve."

Elimine su cerebro de la base de datos. No pregunte cómo acceder a una tabla de referencias cruzadas. Pregunte cómo encontrar a los empleados para un gerente o los gerentes de un empleado.

Si utiliza una subclase personalizada de NSManagedObject, puede declarar las propiedades como documentadas. A continuación, puede decir:

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

Eso no le dará todos los empleados y todos los gerentes, sólo todos los empleados para que el manager y todos los gerentes de ese empleado. Para cambiar las relaciones:

[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 

Sólo tiene que hacer, ya sea uno de cada par de estados, y lo hará de forma implícita los otros, los gerentes y los empleados siempre y cuando se haya definido como inversas entre sí.

Si no utiliza una subclase personalizada, el acceso es un poco más detallado

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.

+5

Esa es una de las mejores respuestas que he visto en desbordamiento de pila. Muchas gracias! Prácticamente tengo lágrimas en los ojos Estaba tan confundido con esto. – Darkenor

+0

De acuerdo, respuesta increíble. –

+2

Ocho jefes ... Ocho, Bob. – meggar

1

La respuesta simple es marcar la relación como uno a muchos desde ambos extremos al configurar los datos principales en xCode. Eso en esencia crea muchos para muchos. Está en los documentos de Apple en algún lugar, pero no puedo encontrar la URL.

+0

Pero, eh, ¿cómo veo qué empleados tienen gerentes y qué gerentes tienen empleados? Quiero decir, ¿serían una gran lista de lo contrario? – Darkenor

+0

Diría employee.managers para obtener un conjunto de gerentes para el empleado. De un gerente, simplemente diría manager.employees y obtenga un conjunto de todas las entidades de empleados para ese gerente. ("empleado" y "gerente" son instancias específicas de una entidad que se refieren a una persona). –

4

Si su pregunta es "cómo podría hacerlo en los datos básicos", la respuesta es exactamente la que usted describe. Cree una relación de muchos en cada entidad y defina cada una como la inversa de la otra.

Si su pregunta es "¿cómo podría funcionar esto?", Puede que le resulte útil consultar la base de datos sqlite que se creó a partir de su modelo para ver cómo se configuran las cosas. CoreData es bastante bueno para hacerlo, así que no debes preocuparte por los detalles, pero si insistes en comprender los detalles, no hay nada que te impida mirar los datos para ver qué está haciendo.

Una vez que tenga esto en su lugar, recorrerá la relación según sea necesario para obtener los atributos que desee. Puede hacerlo en código utilizando instancias de NSManagedObject. Por ejemplo:

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 
} 

En este ejemplo también se puede simplificar usando el acceso directo a la propiedad en lugar de la sintaxis de MVA, pero se entiende la idea.

Si está buscando atravesar esta relación de muchos a muchos más directamente como parte de una consulta de búsqueda, entonces puede hacer algunas cosas con los predicados para obtener lo que desea.Consulte Apple's predicate programming guide para ver ejemplos de lo que puede poner en un predicado

+0

Bueno, saber cómo funciona es bueno, pero lo que realmente quiero saber es cómo acceder a la tabla de referencias cruzadas. Quiero decir, ¿cómo se supone que debes mapear las dos entidades entre sí? Un atributo de una entidad no tiene todos los atributos de la otra entidad. – Darkenor

+0

Actualicé la respuesta un poco para incluir un ejemplo de acceso a los datos de referencia cruzada usando el código. Si está buscando un ejemplo de un tipo específico de consulta, por favor aclare lo que está buscando y posiblemente podamos proporcionar un predicado que pueda usar para lograr lo que desea. –

0

Posiblemente lo que le impida es cómo pasar del dominio del modelo de datos abstracto a un conjunto de objetos que utiliza en el código. Si es así, prueba a utilizar mogenerator:

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

Eso es una utilidad de línea de comandos (no estoy seguro qué tan bien funciona la integración XCode estos días), donde se señala que en un modelo, y le da conjuntos de objetos de datos puedes usar. Debe tener un nombre de objeto establecido para cada entidad además del nombre de la entidad.

Los objetos de datos generados tienen llamadas como employee.managers, lo que le daría un conjunto de entidades de administrador para un empleado, y viceversa.

2

Digamos que tiene dos entidades en su base de datos, empleados y gerentes. Su aspecto sería algo como esto en el código:

@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; 

Así que digamos que quisiera recuperar todos los empleados para gestor de número 1, que sólo tendría que obtener el objeto de administrador de la base de datos:

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]; 

y entonces tendría que todos sus empleados en la propiedad empleados:

NSSet *allHisEmployees = manager.employees; 

sería exactamente el mismo para recuperar los gerentes para un empleado determinado.

espero que aclara las cosas

Cuestiones relacionadas