2009-10-12 9 views
35

Estoy utilizando la aplicación de ejemplo CoreDataBooks de Apple como base para tirar datos en un segundo contexto de objetos gestionados en segundo plano, y luego fusionar esos datos en el objeto administrado principal contexto.intento ilegal de establecer una relación 'xyz' entre objetos en contextos diferentes

Los datos que estoy extrayendo son una entidad Book con una relación de uno a uno con una entidad Owner (llamada "propietario"). La entidad Owner tiene una relación muchos con el Book (llamado "libros").

Mis datos es un documento XML de la forma:

<Owner> 
    <Name>alexpreynolds</Name> 
    <ID>123456</ID> 
</Owner> 
<Books> 
    <Book>Book One</Book> 
    <Book>Book Two</Book> 
    ... 
    <Book>Book N</Book> 
</Books> 

Book One través Book N están asociados con una Owner ("alexpreynolds, 123456").

Estoy analizando esto en una instancia Owner y un NSMutableSet compuesto por Book instancias.

Cuando intento guardar la primera vez, se guarda bien y los datos combinados aparecen en la vista de tabla.

En el segundo guardado, sin embargo, cuando el contenido XML contiene un nuevo libro, no funciona.

Esto es lo que sucede:

Entonces intento cargar en un documento XML que contiene un nuevo Book no está ya en el contexto de objeto gestionado primaria. El nuevo Book está utilizando el mismo Owner que el que está asociado con el otro Book s.

que tienen rutinas que captan a cabo esta Owner objeto administrado única (que ya tengo en mi contexto de objeto gestionado primaria) y la única Book que es no se encuentran en el MOC primaria.

partir de esto, creo un nuevo objeto en el Book MOC secundaria, y establecer su relación "owner" para apuntar a la única Owner que encontré en el MOC primaria.

Cuando guardo, me sale el siguiente error:

*** Terminating app due to uncaught 
exception 'NSInvalidArgumentException', 
reason: 'Illegal attempt to establish a 
relationship 'owner' between objects in 
different contexts 

(source = <Book: 0x7803590> 
(entity: Book; id: 0x7802ae0 <x-coredata:/// 
Book/t527F06B2-3EB5-47CF-9A29-985B0D3758862> 
; data: { 
creationDate = 2009-10-12 06:01:53 -0700; 
name = nil; 
nameInitial = nil; 
operations = (
); 
owner = nil; 
type = 0; 
}) , 

destination = <Owner: 0x78020a0> (entity: 
Owner; id: 0x3a56f80 <x-coredata://043AF2F0-1AD0- 
4078-A5E8-E9D7071D67D1/Owner/p1> ; data: { 
books = "<relationship fault: 0x7801bf0 'books'>"; 
displayName = alexpreynolds; 
ownerID = 123456; 
}))' 

¿Cómo se crea una nueva entidad Book en el MOC secundaria, por lo que todavía puedo asociarlo con un pre-existente Owner en las primarias MOC?

Respuesta

63

No puede haber relaciones entre objetos en diferentes contextos de objetos gestionados. Entonces, una forma de evitarlo es llevar el objeto al contexto del objeto gestionado.

Por ejemplo:

NSManagedObject *book = // get a book in one MOC 
NSManagedObject *owner = // get an owner in a different MOC 
[[owner mutableSetValueForKey:@"books"] addObject:[owner.managedObjectContext objectWithID:[book objectID]]]; 

Así que lo que está haciendo en realidad es buscar el Book en el mismo contexto de objeto gestionado con owner. Tenga en cuenta, sin embargo, que esto solo es posible si book ya se ha guardado. El contexto del objeto administrado va a buscar el objeto en el almacén persistente, por lo que debe guardarse primero.

+0

¡Gracias por esto! Estaba trabajando con Core Data en un subproceso GCD de fondo, así que tenía que tener un fondo NSManagedObject, que había olvidado usar para insertar el objeto principal, ¡así que estaba usando el hilo principal NSManagedObject! ¡Gracias de todos modos! :) – runmad

1

Como dice el error, no está permitido tener una relación en un objeto de Datos básicos cuyo valor esté establecido en otro objeto que se encuentre en un contexto diferente. Una forma de evitar esto es esperar hasta después de guardar el nuevo objeto y volver a fusionarlo en el contexto primario, luego establecer la relación owner según corresponda (ya que ambos objetos están ahora en el mismo contexto, no hay problema con eso) .

+0

Siguiendo el ejemplo de Core Data Books, el MOC secundario se libera después de que se produce la fusión. Si, en cambio, hago del MOC secundario una variable de instancia, el propietario del MOC primario se refiere a los libros en el MOC secundario, que proporciona el mensaje de error. Si tengo un propietario secundario de MOC que se refiere a libros en el MOC secundario, cuando me fusiono ahora tengo instancias duplicadas de propietario, lo cual no es correcto. Idealmente, podría asociarme con un propietario existente. Si tiene tiempo, ¿podría explicar su respuesta con un poco más de detalle? –

8

Tuve el mismo problema y esta frase me ayudó a resolver el error.

You can't have relationships between objects in different managed object contexts. So one way of getting around that is to bring the object into the managed object context.

Aquí está mi código (que sustituyen las variables para hacer que funcione para usted):

// Have the owner object and get the managedObjectContext 
Owner *owner = [[DataFunctions alloc] getCurrentOwner]; 
NSManagedObjectContext *context = [owner managedObjectContext]; 

// Create a book and use the manageObjectContext of owner 
Book *book = [NSEntityDescription insertNewObjectForEntityForName:@"Book" inManagedObjectContext:context]; 
[newQuote setValue: "Book Title" forKey:@"title"]; 
[newQuote setOwner:owner]; 

Espero que esto ayude :)

0
book *book = [mainContext ........] //Get book from default context 

NSManagedObjectID *objectId = [book objectID]; 

Book *tmpBook = [tmpContext objectWithID:objectId]; //Now book has the legal relationship 
3

Aquí, usted está tratando de establecer una relación entre dos objetos que se buscan/crean con un contexto diferente. Los datos principales no le permitirán establecer tales relaciones. Para lograr esto, debe buscar el segundo objeto (con el que intenta establecer una relación) con el contexto del primer objeto con objectID. Ahora deberías poder establecer una relación entre estos dos objetos. Por ejemplo:

MagicalRecord.saveWithBlock({[unowned self] (localContext: NSManagedObjectContext!) in 

    let user = User.MR_createEntityInContext(localContext)! 
    ..... 
    ..... 
}) //here local context stores data on end of block itself 

MagicalRecord.saveWithBlock({[unowned self] (localContext: NSManagedObjectContext!) in 

    let address = Address.MR_createEntityInContext(localContext)! 
    ..... 
    ..... 
    let user = localContext.objectWithID(self.user!.objectID) as! User 
    user.address = address 
}) 

Espero que esto te ayude!

Cuestiones relacionadas