web-dev-qa-db-ja.com

異なるコンテキストのオブジェクト間に関係「xyz」を確立しようとする不正な試み

AppleのCoreDataBooksサンプルアプリケーションを、バックグラウンドでセカンダリ管理オブジェクトコンテキストにデータをプルし、そのデータをプライマリ管理オブジェクトコンテキストにマージするための基礎として使用しています。

私が取り込んでいるデータは、Bookエンティティ(「所有者」と呼ばれます)と1対1の関係を持つ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 One 使って Book Nは1つのOwner"alexpreynolds, 123456")。

これをOwnerインスタンスと、NSMutableSetインスタンスで構成されるBookに解析しています。

初めて保存しようとすると、正常に保存され、マージされたデータがテーブルビューに表示されます。

ただし、2番目の保存では、XMLコンテンツに新しい本が含まれている場合、それは機能しません。

ここで何が起こるかです:

次に、プライマリ管理オブジェクトコンテキストにまだない新しいBookを含むXMLドキュメントをロードしようとします。新しいBookは、他のOwnersに関連付けられているものと同じBookを使用しています。

この一意のOwner管理対象オブジェクト(既にプライマリ管理オブジェクトコンテキストにある)とnotである一意の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と関連付けられるようにするにはどうすればよいですか?

44
Alex Reynolds

異なる管理対象オブジェクトコンテキスト内のオブジェクト間に関係を持つことはできません。したがって、これを回避する1つの方法は、オブジェクトを管理オブジェクトコンテキストに取り込むことです。

例えば:

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

したがって、実際に行っているのは、Bookownerと同じ管理対象オブジェクトコンテキストにフェッチすることです。ただし、これはbookがすでに保存されている場合にのみ可能であることを覚えておいてください。管理対象オブジェクトコンテキストは永続ストアでオブジェクトを探すため、最初に保存する必要があります。

69
Alex

私は同じ問題を抱えていて、この文章は私がエラーを解決するのに役立ちました。

異なる管理対象オブジェクトコンテキスト内のオブジェクト間に関係を持つことはできません。したがって、これを回避する1つの方法は、オブジェクトを管理オブジェクトコンテキストに取り込むことです。

これが私のコードです(あなたのために機能させるために変数を置き換えました):

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

これが役に立てば幸いです:)

10
Kenneth John

ここでは、異なるコンテキストでフェッチ/作成された2つのオブジェクト間の関係を確立しようとしています。コアデータでは、このような関係を確立することはできません。これを実現するには、objectIDを持つ最初のオブジェクトのコンテキストで2番目のオブジェクト(関係を作成しようとしている)をフェッチする必要があります。これで、これら2つのオブジェクト間の関係を確立できるはずです。例えば:

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

これがあなたに役立つことを願っています!

4
shripad20

エラーが示すように、別のコンテキストで保持されている別のオブジェクトに値が設定されている1つのCore Dataオブジェクトに関係を持つことはできません。これを回避する1つの方法は、新しいオブジェクトを保存してプライマリコンテキストにマージするまで待機し、次にowner関係を適切に設定することです(両方のオブジェクトが同じコンテキストにあるため、問題ありません)。

2
Tim

Swiftバージョン...

context.insert(objectFromOtherContext)
1
Justin Domnitz
book *book = [mainContext ........]   //Get book from default context

NSManagedObjectID *objectId = [book objectID];

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