すべてのコアデータリレーションシップにはインバースが必要ですか?


150

2つのエンティティクラスがあるSocialAppとします。SocialAppType

SocialApp:私は1つの属性持っているappURLと1人の関係を:type

SocialAppType、私は3つの属性を持っている:baseURLnamefavicon

SocialApp関係の宛先typeは、の単一のレコードですSocialAppType

例として、複数のFlickrアカウントの場合、多数のSocialAppレコードがあり、各レコードには個人のアカウントへのリンクが保持されます。SocialAppType「Flickr」タイプには、すべてのSocialAppレコードが指す1つのレコードがあります。

私はこのスキーマを使用してアプリケーションを構築するとの間には逆相関がないことを、私は警告を受けるSocialAppTypeとはSocialApp

 /Users/username/Developer/objc/TestApp/TestApp.xcdatamodel:SocialApp.type: warning: SocialApp.type -- relationship does not have an inverse

私は逆が必要ですか、そしてなぜですか?

回答:


117

実際には、少なくとも私が知っていることですが、インバースがないためにデータが失われることはありません。簡単なグーグルはあなたがそれらを使うべきであることを提案します:

逆の関係は、物事をより整頓するだけでなく、データの整合性を維持するためにCore Dataによって実際に使用されます。

- ココアDev Central

通常、両方向の関係をモデル化し、逆の関係を適切に指定する必要があります。Core Dataは、この情報を使用して、変更が加えられた場合にオブジェクトグラフの一貫性を確保します(「関係とオブジェクトグラフの整合性の操作」を参照)。両方向の関係をモデル化したくない理由と、そうでない場合に発生する可能性のある問題のいくつかについては、「単方向の関係」を参照してください。

- コアデータプログラミングガイド


5
逆リレーションシップがデータの整合性を維持するのに役立つというドキュメントの意味の詳細な説明については、MadNikの回答(私がこれを書いている時点でページの下部にあります)を参照してください。
Mark Amery 2013

135

Appleのドキュメントには、逆の関係を持たないことによって問題が発生する可能性がある状況を示唆する素晴らしい例があります。このケースにマッピングしてみましょう。

次のようにモデル化したとします。 ここに画像の説明を入力してください

あなたが持っている注意に-1「と呼ばれる関係タイプから、」SocialAppSocialAppType。この関係はオプションではなく、「拒否」削除規則があります。

次のことを考えてみましょう。

SocialApp *socialApp;
SocialAppType *appType;
// assume entity instances correctly instantiated

[socialApp setSocialAppType:appType];
[managedObjectContext deleteObject:appType];
BOOL saved = [managedObjectContext save:&error];

リレーションシップがオプションではないときに削除ルールを拒否として設定しているため、このコンテキストの保存に失敗することが予想されます。

しかし、ここで保存は成功します。

その理由は、逆の関係を設定していないからです。そのため、appTypeを削除してもsocialAppインスタンスは変更済みとしてマークされません。そのため、保存する前にsocialAppの検証は行われません(変更が発生していないため、検証は不要であると想定しています)。しかし、実際には変化が起こりました。しかし、それは反映されません。

appTypeを

SocialAppType *appType = [socialApp socialAppType];

appTypeはnilです。

変だよね?オプションではない属性に対してnilを取得しますか?

したがって、逆の関係を設定していれば問題はありません。それ以外の場合は、次のようにコードを記述して検証を強制する必要があります。

SocialApp *socialApp;
SocialAppType *appType;
// assume entity instances correctly instantiated

[socialApp setSocialAppType:appType];
[managedObjectContext deleteObject:appType];

[socialApp setValue:nil forKey:@"socialAppType"]
BOOL saved = [managedObjectContext save:&error];

9
これは素晴らしい答えです。何が-ドキュメントから、そして私が読んだすべてから-逆の関係が人間にとって意味のないものであっても、すべての逆を持っていることを支持する主な議論を明確に詳しく述べてくれてありがとう これは本当に受け入れられるべき答えです。このすべての質問スレッドが欠落しているのは、Rose Perroneの回答(およびドキュメントでも少し)で触れられている、インバースを持たないことを選択する理由のより詳細な調査です。
Mark Amery

46

Dave MarkとJeff LeMarcheによるMore iPhone 3 Developmentで見つけた決定的な答えを言い換えます。

アプリでは通常、逆関係を使用しない場合でも、常に逆を作成して指定することをお勧めします。このため、インバースを提供できない場合は警告が表示されます。

逆関係がパフォーマンスに悪影響を与える可能性があるシナリオがいくつかあるため、関係に逆関係がある必要はありません。たとえば、逆の関係に非常に多数のオブジェクトが含まれているとします。逆を削除するには、逆を表すセットを反復する必要があり、パフォーマンスが低下します。

ただし、特別な理由がない限り、逆をモデル化してください。Core Dataがデータの整合性を確保するのに役立ちます。パフォーマンスの問題が発生した場合、後で逆関係を削除するのは比較的簡単です。


24

より良い質問は、「逆を持たない理由はあるのか」ということです。Core Dataは実際にはオブジェクトグラフ管理フレームワークであり、永続化フレームワークではありません。つまり、その目的は、オブジェクトグラフ内のオブジェクト間の関係を管理することです。逆の関係は、これをはるかに簡単にします。そのため、Core Dataは逆の関係を想定しており、そのユースケース用に作成されています。それらがなければ、オブジェクトグラフの一貫性を自分で管理する必要があります。特に、逆関係のない多対多の関係は、物事がうまく機能し続けるため一生懸命働いていない限り、コアデータによって破損する可能性が非常に高くなります。逆の関係のディスクサイズに関するコストは、それが得られる利点と比較すると、ほんのわずかです。


20

オブジェクトグラフの維持を処理する2つのオブジェクト間に別のコアデータ関係が既に存在する場合、逆のないコアデータ関係に対して良いケースを作成できるシナリオが少なくとも1つあります。

たとえば、1つの本に1つのページが含まれているのに、本には多くのページが含まれています。これは、双方向の多対1の関係です。ページを削除すると関係が無効になるだけですが、本を削除するとページも削除されます。

ただし、各本について現在読み取られているページを追跡することもできます。これはPageの "currentPage" プロパティで実行できますが、ブック内の1つのページだけがいつでも現在のページとしてマークされるようにするには、他のロジックが必要です。代わりに、Bookから単一のページにcurrentPage 関係を作成すると、常に現在のページが1つだけマークされ、さ​​らにこのページには、book.currentPageだけでブックを参照して簡単にアクセスできます。

ブックとページの間のコアデータ関係のグラフィック表示

この場合、相互関係はどうなるでしょうか?主に無意味なもの。「myBook」などは逆方向に追加することもできますが、ページの「book」関係にすでに含まれている情報しか含まれていないため、独自のリスクが生じます。おそらく将来的には、これらの関係の1つを使用する方法が変更され、コアデータ構成が変更されることになります。page.bookがコードで使用されているはずの場所でpage.myBookが使用されている場合、問題が発生する可能性があります。これを積極的に回避する別の方法は、ページへのアクセスに使用されるNSManagedObjectサブクラスでmyBookを公開しないことです。ただし、そもそも逆をモデル化しない方が簡単であると主張できます。

概説した例では、「Nullify」との相互関係がないため、currentPage関係の削除規則を「No Action」または「Cascade」に設定する必要があります。(Cascadeは、本を読んでいるときに本のすべてのページを引き裂いていることを意味しますが、特に寒くて燃料が必要な場合は、それが当てはまる可能性があります。)

この例のように、オブジェクトグラフの整合性が危険にさらされておらず、コードの複雑さと保守性が向上していることを示すことができる場合、逆のない関係が正しい決定であると主張できます。


Duncanに感謝します。これは私が持っているユースケースに非常に近いものです。基本的に、私は本の最後のページを取得できる必要があります。これを永続的な値にして、フェッチ述部で使用できるようにする必要があります。「bookIAmLastPageOf」インバースを設定しましたが、それはかなり無意味であり、他の問題を引き起こしています(私は正しく理解していません)。単一のケースの警告を無効にする方法があるかどうか知っていますか?
ベンジョン

警告を無効にする方法はありますか?私は現在2 を持っています。...逆あり、アクションなしの削除ルールが必要です...削除されたオブジェクトとの関係が生じる可能性があります。そして、次のcurrentPageようにマークできますOptionalか?
SwiftArchitect 2015年

currentPageを関係ではなくNSManagedObjectIDとして保存することは有効なアプローチでしょうか?
user965972

4

ドキュメントはインバースを必要としないようですが、私はインバースを持たないことによって実際に「データ損失」を引き起こすシナリオを解決しました。レポート可能なオブジェクトと多対多の関係を持つレポートオブジェクトがあります。逆の関係がないと、再起動時に対多関係への変更は失われます。コアデータのデバッグを調べた後、レポートオブジェクトを保存していても、オブジェクトグラフ(関係)が更新されていないことが明らかになりました。私はそれを使用していませんが、逆を追加しました。したがって、それが必須であるとは言えないかもしれませんが、逆行列のない関係は、奇妙な副作用を確実にもたらす可能性があります。


0

Object Integrity逆も使用されます(他の理由で、他の回答を参照してください):

推奨されるアプローチは、両方向の関係をモデル化し、逆の関係を適切に指定することです。Core Dataはこの情報を使用して、変更が行われた場合にオブジェクトグラフの一貫性を確保します

送信元:https : //developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreData/HowManagedObjectsarerelated.html#//apple_ref/doc/uid/TP40001075-CH17-SW1

提供されたリンクは、なぜinverseセットが必要なのかについてのアイデアを提供します。それがなければ、データ/完全性を失う可能性があります。また、オブジェクトにアクセスするnil可能性が高くなります。


0

一般に、逆の関係は必要ありません。しかし、コアデータには、逆の関係を必要とする癖/バグはほとんどありません。コンテキストの保存中にエラーがなくても、逆の関係が欠落していると、関係/オブジェクトが欠落する場合があります。コアデータの操作中に、オブジェクトが見つからないこととその回避方法を示すために作成したこの例を確認してください

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.