【问题标题】:Illegal attempt to establish a relationship 'xyz' between objects in different contexts非法尝试在不同上下文中的对象之间建立关系“xyz”
【发布时间】:2010-12-05 23:49:45
【问题描述】:

我使用 Apple 的 CoreDataBooks 示例应用程序作为基础,在后台将数据拉入辅助托管对象上下文,然后将该数据合并到主要托管对象上下文中。

我要提取的数据是一个 Book 实体,它与一个 Owner 实体(称为“所有者”)具有一对一的关系。 Owner 实体与Book 具有一对多关系(称为“书籍”)。

我的数据是一个 XML 格式的文档:

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

Book OneBook N 与一个 Owner ("alexpreynolds, 123456") 相关联。

我将其解析为一个Owner 实例和一个由Book 实例组成的NSMutableSet

当我第一次尝试保存时,它保存得很好,合并的数据显示在表格视图中。

然而,在第二次保存时,当 XML 内容包含一本新书时,它就不起作用了。

会发生什么:

然后,我尝试加载一个 XML 文档,该文档包含一个新的Book,该新的Book 尚未在主托管对象上下文中。新的Book 使用与其他Books 关联的Owner

我有例程可以挑选出这个独特的Owner 托管对象(我已经在我的主要托管对象上下文中拥有)和独特的Book没有在主要 MOC 中找到。

据此,我在辅助 MOC 中创建了一个新的 Book 对象,并将其“owner”关系设置为指向我在主 MOC 中找到的唯一 Owner

保存时出现以下错误:

*** 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;
}))'

如何在辅助 MOC 中创建新的 Book 实体,以便我仍然可以将其与主 MOC 中预先存在的 Owner 关联?

【问题讨论】:

    标签: iphone core-data nsfetchedresultscontroller


    【解决方案1】:

    正如错误所说,您不允许在一个 Core Data 对象中建立关系,该对象的值设置为在不同上下文中保存的另一个对象。解决此问题的一种方法是等到保存新对象并将其合并回主上下文之后,然后适当地设置owner 关系(因为两个对象现在都在同一个上下文中,所以没有问题那个)。

    【讨论】:

    • 按照 Core Data Books 示例,在合并发生后释放辅助 MOC。如果我改为将辅助 MOC 设为实例变量,则主 MOC 的所有者指的是辅助 MOC 中的书籍,这会给出错误消息。如果我有一个二级 MOC 所有者引用二级 MOC 中的书籍,那么当我合并时,我现在有重复的所有者实例,这是不正确的。理想情况下,我将能够与现有所有者联系。如果您有时间,能否请您更详细地解释一下您的答案?
    【解决方案2】:

    您不能在不同托管对象上下文中的对象之间建立关系。所以解决这个问题的一种方法是将对象带入托管对象上下文。

    例如:

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

    所以你正在做的实际上是将Book 提取到与owner 相同的托管对象上下文中。但请记住,这只有在 book 已经被保存时才有可能。托管对象上下文将在持久存储中查找对象,因此必须先保存它。

    【讨论】:

    • 谢谢!我在后台 GCD 线程中使用 Core Data,所以必须有一个后台 NSManagedObject,我忘记使用它来插入父对象,所以它使用的是主线程 NSManagedObject!不管怎样,谢谢! :)
    【解决方案3】:

    我遇到了同样的问题,这句话帮我解决了错误。

    您不能在不同托管的对象之间建立关系 对象上下文。所以解决这个问题的一种方法是带上 对象放入托管对象上下文中。

    这是我的代码(我替换了变量以使其适合您):

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

    我希望这会有所帮助:)

    【讨论】:

      【解决方案4】:
      book *book = [mainContext ........]   //Get book from default context
      
      NSManagedObjectID *objectId = [book objectID];
      
      Book *tmpBook = [tmpContext objectWithID:objectId]; //Now book has the legal relationship
      

      【讨论】:

        【解决方案5】:

        在这里,您尝试在使用不同上下文获取/创建的两个对象之间建立关系。核心数据不允许你建立这样的关系。为此,您应该使用具有 objectID 的第一个对象的上下文来获取第二个对象(您试图与之建立关系)。现在您应该能够在这两个对象之间建立关系。例如:

        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
        })
        

        希望对您有所帮助!

        【讨论】:

          【解决方案6】:

          Swift 版本...

          context.insert(objectFromOtherContext)
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-08-31
            • 1970-01-01
            • 1970-01-01
            • 2012-08-16
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多