Apakah setiap Hubungan Data Inti harus memiliki Pembalikan?

150

Katakanlah saya memiliki dua kelas Entitas: SocialAppdanSocialAppType

Dalam SocialAppSaya punya satu Atribut: appURLdan satu Hubungan: type.

Dalam SocialAppTypeSaya memiliki tiga Atribut: baseURL, namedan favicon.

Tujuan SocialApphubungan typeadalah satu rekaman di SocialAppType.

Sebagai contoh, untuk beberapa akun Flickr, akan ada sejumlah SocialAppcatatan, dengan setiap catatan memegang tautan ke akun seseorang. Akan ada satu SocialAppTypecatatan untuk tipe "Flickr", yang akan ditunjukkan oleh semua SocialApprekaman.

Ketika saya membangun aplikasi dengan skema ini, saya mendapat peringatan bahwa tidak ada hubungan terbalik antara SocialAppTypedan SocialApp.

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

Apakah saya perlu invers, dan mengapa?

Alex Reynolds
sumber

Jawaban:

117

Dalam praktiknya, saya belum kehilangan data karena tidak memiliki invers - setidaknya yang saya ketahui. Google cepat menyarankan Anda harus menggunakannya:

Hubungan terbalik tidak hanya membuat segalanya lebih rapi, itu sebenarnya digunakan oleh Core Data untuk menjaga integritas data.

- Cocoa Dev Central

Anda biasanya harus memodelkan hubungan di kedua arah, dan menentukan hubungan terbalik secara tepat. Data Inti menggunakan informasi ini untuk memastikan konsistensi grafik objek jika ada perubahan (lihat “Memanipulasi Hubungan dan Integritas Grafik Objek”). Untuk diskusi tentang beberapa alasan mengapa Anda mungkin tidak ingin membuat model hubungan di kedua arah, dan beberapa masalah yang mungkin muncul jika Anda tidak, lihat "Hubungan Searah."

- Panduan Pemrograman Data Inti

Matthew Schinckel
sumber
5
Lihat jawaban MadNik (di bagian bawah halaman saat saya menulis ini) untuk penjelasan yang lebih menyeluruh tentang apa yang dimaksud dokumen ketika mereka mengatakan bahwa hubungan terbalik membantu menjaga integritas data.
Mark Amery
135

Dokumentasi Apple memiliki contoh hebat yang menyarankan situasi di mana Anda mungkin memiliki masalah dengan tidak memiliki hubungan terbalik. Mari kita petakan dalam case ini.

Asumsikan Anda memodelkannya sebagai berikut: masukkan deskripsi gambar di sini

Perhatikan bahwa Anda memiliki hubungan ke-satu yang disebut " ketik ", dari SocialApphingga SocialAppType. Hubungan ini non-opsional dan memiliki aturan penghapusan "tolak" .

Sekarang pertimbangkan hal berikut:

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

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

Apa yang kami harapkan adalah gagal menyimpan konteks ini karena kami telah menetapkan aturan hapus sebagai Tolak sementara hubungan tidak opsional.

Tapi di sini penyelamatan berhasil.

Alasannya adalah bahwa kami belum menetapkan hubungan terbalik . Karena itu, instance socialApp tidak ditandai sebagai diubah ketika appType dihapus. Jadi tidak ada validasi yang terjadi untuk socialApp sebelum disimpan (ini mengasumsikan tidak diperlukan validasi karena tidak ada perubahan yang terjadi). Namun sebenarnya perubahan terjadi. Tapi itu tidak tercermin.

Jika kami mengingat appType oleh

SocialAppType *appType = [socialApp socialAppType];

appType tidak ada.

Aneh, bukan? Kami mendapat nihil untuk atribut non-opsional?

Jadi Anda tidak berada dalam masalah jika Anda telah mengatur hubungan terbalik. Kalau tidak, Anda harus melakukan validasi paksa dengan menulis kode sebagai berikut.

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];
MadNik
sumber
9
Ini jawaban yang bagus; terima kasih telah menguraikan dengan jelas apa itu - dari dokumen, dan dari semua yang saya baca - argumen utama yang mendukung invers untuk segalanya, bahkan di mana hubungan terbalik tidak bermakna secara manusiawi. Ini seharusnya jawaban yang diterima. Semua utas pertanyaan ini tidak ada sekarang adalah penjelajahan yang lebih terperinci tentang alasan mengapa Anda mungkin memilih untuk tidak memiliki inversi, disinggung dalam jawaban Rose Perrone (dan juga dalam dokumentasi, sedikit).
Mark Amery
46

Saya akan memparafrasekan jawaban pasti yang saya temukan di More iPhone 3 Development oleh Dave Mark dan Jeff LeMarche.

Apple umumnya merekomendasikan agar Anda selalu membuat dan menentukan invers, bahkan jika Anda tidak menggunakan hubungan invers dalam aplikasi Anda. Untuk alasan ini, ini memperingatkan Anda ketika Anda gagal memberikan invers.

Hubungan tidak harus memiliki invers, karena ada beberapa skenario di mana hubungan terbalik dapat merusak kinerja. Sebagai contoh, misalkan hubungan terbalik mengandung sejumlah besar objek. Menghapus invers membutuhkan iterasi pada set yang mewakili kinerja invers, yang melemah.

Tetapi kecuali jika Anda memiliki alasan khusus untuk tidak melakukannya, buat model terbalik . Ini membantu Core Data memastikan integritas data. Jika Anda mengalami masalah kinerja, relatif mudah untuk menghapus hubungan terbalik nanti.

Rose Perrone
sumber
24

Pertanyaan yang lebih baik adalah, "adakah alasan untuk tidak memiliki kebalikan"? Data Inti benar-benar merupakan kerangka kerja manajemen grafik objek, bukan kerangka kerja persistensi. Dengan kata lain, tugasnya adalah mengelola hubungan antar objek dalam grafik objek. Hubungan terbalik membuat ini lebih mudah. Untuk alasan itu, Data Inti mengharapkan hubungan terbalik dan ditulis untuk kasus penggunaan itu. Tanpa mereka, Anda harus mengelola sendiri konsistensi grafik objek. Secara khusus, hubungan ke-banyak tanpa hubungan terbalik sangat mungkin rusak oleh Data Inti kecuali jika Anda bekerja sangat keras untuk menjaga hal-hal berfungsi. Biaya dalam hal ukuran disk untuk hubungan terbalik benar-benar tidak signifikan dibandingkan dengan manfaat yang didapatnya bagi Anda.

Barry Wark
sumber
20

Setidaknya ada satu skenario di mana kasus yang baik dapat dibuat untuk hubungan data inti tanpa terbalik: ketika ada hubungan data inti lain antara dua objek yang sudah ada, yang akan menangani pemeliharaan grafik objek.

Misalnya, sebuah buku berisi banyak halaman, sementara satu halaman ada dalam satu buku. Ini adalah hubungan dua arah banyak-ke-satu. Menghapus halaman hanya membatalkan hubungan, sedangkan menghapus buku juga akan menghapus halaman.

Namun, Anda mungkin juga ingin melacak halaman yang sedang dibaca untuk setiap buku. Ini dapat dilakukan dengan "currentPage" properti di Halaman , tapi kemudian Anda perlu logika lain untuk memastikan bahwa hanya satu halaman dalam buku tersebut ditandai sebagai halaman saat setiap saat. Alih-alih, membuat hubungan currentPage dari Buku ke satu halaman akan memastikan bahwa akan selalu ada hanya satu halaman saat ini yang ditandai, dan selanjutnya bahwa halaman ini dapat diakses dengan mudah dengan referensi ke buku hanya dengan book.currentPage.

Presentasi grafis hubungan data inti antara buku dan halaman

Akan seperti apa hubungan timbal balik dalam kasus ini? Sesuatu yang tidak masuk akal. "myBook" atau yang serupa dapat ditambahkan kembali ke arah lain, tetapi hanya berisi informasi yang sudah terkandung dalam hubungan "buku" untuk halaman, dan dengan demikian menciptakan risiko sendiri. Mungkin di masa depan, cara Anda menggunakan salah satu dari hubungan ini diubah, menghasilkan perubahan dalam konfigurasi data inti Anda. Jika page.myBook telah digunakan di beberapa tempat di mana page.book seharusnya digunakan dalam kode, mungkin ada masalah. Cara lain untuk menghindari hal ini secara proaktif juga adalah dengan tidak mengekspos myBook di subkelas NSManagedObject yang digunakan untuk mengakses halaman. Namun, dapat dikatakan bahwa lebih mudah untuk tidak memodelkan invers di tempat pertama.

Dalam contoh yang diuraikan, aturan hapus untuk hubungan currentPage harus diatur ke "No Action" atau "Cascade", karena tidak ada hubungan timbal balik ke "Nullify". (Cascade menyiratkan bahwa Anda merobek setiap halaman buku saat Anda membacanya, tetapi itu mungkin benar jika Anda sangat dingin dan membutuhkan bahan bakar.)

Ketika dapat ditunjukkan bahwa integritas grafik objek tidak berisiko, seperti dalam contoh ini, dan kompleksitas kode dan rawatan ditingkatkan, dapat dikatakan bahwa hubungan tanpa invers mungkin merupakan keputusan yang tepat.

Duncan Babbage
sumber
Terima kasih Duncan - ini sangat dekat dengan use case yang saya miliki. Intinya, saya harus bisa mendapatkan halaman terakhir buku. Saya ingin ini menjadi nilai yang bertahan sehingga saya dapat menggunakannya dalam predikat pengambilan. Saya telah membuat inversi "bookIAmLastPageOf", tetapi cukup tidak masuk akal dan menyebabkan masalah lain (saya tidak mengerti dengan benar). Apakah Anda tahu jika ada cara untuk menonaktifkan peringatan untuk satu kasus?
Benjohn
Apakah ada cara untuk menonaktifkan peringatan? Saya sekarang memiliki 2: ... harus memiliki kebalikan dan Tidak Ada Tindakan Hapus Aturan ... dapat mengakibatkan hubungan ke objek yang dihapus . Dan dapat currentPageditandai sebagai Optional?
SwiftArchitect
Apakah menyimpan Halaman saat ini sebagai NSManagedObjectID alih-alih hubungan menjadi pendekatan yang valid?
user965972
4

Meskipun dokumen tampaknya tidak memerlukan invers, saya baru saja menyelesaikan skenario yang ternyata menghasilkan "kehilangan data" dengan tidak memiliki invers. Saya memiliki objek laporan yang memiliki banyak hubungan pada objek yang dapat dilaporkan. Tanpa hubungan terbalik, perubahan apa pun pada hubungan ke-banyak hilang saat diluncurkan kembali. Setelah memeriksa debug Data Inti, tampak jelas bahwa meskipun saya menyimpan objek laporan, pembaruan ke grafik objek (hubungan) tidak pernah dibuat. Saya menambahkan invers, meskipun saya tidak menggunakannya, dan voila, itu berfungsi. Jadi mungkin tidak mengatakan itu diperlukan tetapi hubungan tanpa terbalik pasti dapat memiliki efek samping yang aneh.

greg
sumber
0

Inversi juga digunakan untuk Object Integrity(karena alasan lain, lihat jawaban lain):

Pendekatan yang disarankan adalah memodelkan hubungan di kedua arah dan menentukan hubungan terbalik secara tepat. Data Inti menggunakan informasi ini untuk memastikan konsistensi grafik objek jika perubahan dilakukan

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

Tautan yang disediakan memberi Anda ide mengapa Anda harus memiliki satu inverseset. Tanpa itu, Anda dapat kehilangan data / integritas. Juga, kemungkinan Anda mengakses objek yang nillebih mungkin.

J. Doe
sumber
0

Tidak perlu untuk hubungan terbalik secara umum. Tetapi ada beberapa kebiasaan / bug dalam data Core di mana Anda memerlukan hubungan terbalik. Ada kasus di mana hubungan / objek hilang, meskipun tidak ada kesalahan saat menyimpan konteks, jika ada hubungan terbalik yang hilang. Lihat contoh ini , yang saya buat untuk mendemonstrasikan objek yang hilang dan cara mengatasinya, saat bekerja dengan data Core

Dhilip
sumber