Core Data ทุกความสัมพันธ์ต้องมี Inverse หรือไม่?


150

สมมติว่าฉันมี Entity สองคลาส: SocialAppและSocialAppType

ในSocialAppฉันมีหนึ่งคุณลักษณะ: appURLและหนึ่งความสัมพันธ์: type.

ในSocialAppTypeฉันมีสามคุณสมบัติ: baseURL, และnamefavicon

ปลายทางของSocialAppความสัมพันธ์เป็นบันทึกเดียวในtypeSocialAppType

ตัวอย่างเช่นสำหรับบัญชี Flickr หลายบัญชีจะมีจำนวนSocialAppเรคคอร์ดโดยแต่ละเรคคอร์ดจะมีลิงค์ไปยังบัญชีของบุคคล จะมีหนึ่งSocialAppTypeระเบียนสำหรับประเภท "Flickr" ซึ่งSocialAppระเบียนทั้งหมดจะชี้ไปที่

เมื่อฉันสร้างโปรแกรมประยุกต์กับคีมานี้ผมได้รับการเตือนว่าไม่มีความสัมพันธ์แบบผกผันระหว่างและSocialAppTypeSocialApp

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

ฉันต้องการสิ่งที่ตรงกันข้ามหรือไม่และทำไม?

คำตอบ:


117

ในทางปฏิบัติฉันไม่ได้สูญเสียข้อมูลใด ๆ เนื่องจากไม่มีสิ่งที่ตรงกันข้าม - อย่างน้อยฉันก็รู้ Google ฉบับย่อแนะนำให้คุณใช้:

ความสัมพันธ์แบบผกผันไม่เพียง แต่ทำให้เป็นระเบียบมากขึ้น แต่จริงๆแล้วมันใช้โดย Core Data เพื่อรักษาความสมบูรณ์ของข้อมูล

- Cocoa Dev Central

โดยทั่วไปคุณควรเป็นแบบอย่างความสัมพันธ์ในทั้งสองทิศทางและระบุความสัมพันธ์ผกผันอย่างเหมาะสม ข้อมูลหลักใช้ข้อมูลนี้เพื่อรับรองความสอดคล้องของกราฟวัตถุหากมีการเปลี่ยนแปลง (ดูที่ "การจัดการความสัมพันธ์และความสมบูรณ์ของกราฟวัตถุ") สำหรับการอภิปรายถึงสาเหตุบางประการที่ทำให้คุณไม่ต้องการสร้างแบบจำลองความสัมพันธ์ทั้งสองทิศทางและปัญหาบางอย่างที่อาจเกิดขึ้นหากคุณไม่เห็น "ความสัมพันธ์แบบทิศทางเดียว"

- คู่มือการเขียนโปรแกรมคอร์ข้อมูล


5
ดูคำตอบของ MadNik (ที่ด้านล่างของหน้าในขณะที่ฉันกำลังเขียน) สำหรับคำอธิบายอย่างละเอียดมากขึ้นว่าเอกสารหมายถึงอะไรเมื่อพวกเขาพูดว่าความสัมพันธ์แบบผกผันช่วยรักษาความสมบูรณ์ของข้อมูล
Mark Amery

135

เอกสารประกอบของ Apple มีตัวอย่างที่ดีที่แนะนำสถานการณ์ที่คุณอาจมีปัญหาโดยไม่มีความสัมพันธ์แบบผกผัน ลองแมปลงในกรณีนี้

สมมติว่าคุณสร้างแบบจำลองดังต่อไปนี้: ป้อนคำอธิบายรูปภาพที่นี่

หมายเหตุคุณมีต่อหนึ่งความสัมพันธ์ที่เรียกว่า " ประเภท " จากไปSocialApp SocialAppTypeความสัมพันธ์คือไม่เลือกและมี"ปฏิเสธ" กฎลบ

ตอนนี้ให้พิจารณาสิ่งต่อไปนี้:

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

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

สิ่งที่เราคาดว่าจะล้มเหลวในการบันทึกบริบทนี้เนื่องจากเราได้ตั้งกฎการลบเป็นปฏิเสธในขณะที่ความสัมพันธ์นั้นไม่จำเป็น

แต่ที่นี่การบันทึกสำเร็จ

เหตุผลก็คือว่าเราไม่ได้ตั้งค่าความสัมพันธ์แบบผกผัน ด้วยเหตุนั้นอินสแตนซ์ของ SocialApp จึงไม่ได้รับการทำเครื่องหมายว่ามีการเปลี่ยนแปลงเมื่อลบ appType ดังนั้นจึงไม่มีการตรวจสอบความถูกต้องเกิดขึ้นสำหรับ socialApp ก่อนการบันทึก (มันไม่จำเป็นต้องทำการตรวจสอบความถูกต้องเนื่องจากไม่มีการเปลี่ยนแปลงเกิดขึ้น) แต่จริงๆแล้วมีการเปลี่ยนแปลงเกิดขึ้น แต่มันก็ไม่ได้สะท้อนออกมา

ถ้าเราจำ appType โดย

SocialAppType *appType = [socialApp socialAppType];

appType ไม่มีศูนย์

แปลกใช่มั้ย เราได้รับศูนย์สำหรับแอตทริบิวต์ที่ไม่ใช่ตัวเลือก?

ดังนั้นคุณจะไม่มีปัญหาหากคุณตั้งค่าความสัมพันธ์แบบผกผัน มิฉะนั้นคุณต้องทำการบังคับให้มีการตรวจสอบโดยการเขียนรหัสดังนี้

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

ฉันจะถอดความคำตอบที่ชัดเจนที่ฉันพบในMore iPhone 3 Developmentโดย Dave Mark และ Jeff LeMarche

โดยทั่วไปแล้ว Apple แนะนำให้คุณสร้างและระบุค่าผกผันเสมอแม้ว่าคุณจะไม่ได้ใช้ความสัมพันธ์แบบผกผันในแอปของคุณก็ตาม ด้วยเหตุนี้มันจึงเตือนคุณเมื่อคุณไม่ได้ให้ค่าผกผัน

ความสัมพันธ์ไม่จำเป็นต้องมีการผกผันเนื่องจากมีบางสถานการณ์ที่ความสัมพันธ์แบบผกผันอาจส่งผลกระทบต่อประสิทธิภาพการทำงาน ตัวอย่างเช่นสมมติว่าความสัมพันธ์ผกผันมีวัตถุจำนวนมาก การลบค่าผกผันต้องทำซ้ำในชุดที่แสดงถึงค่าผกผันและประสิทธิภาพลดลง

แต่ถ้าคุณไม่มีเหตุผลที่เฉพาะเจาะจงให้ทำแบบจำลองอินเวอร์ส ช่วยให้ Core Data รับรองความถูกต้องของข้อมูล หากคุณพบปัญหาเกี่ยวกับประสิทธิภาพการลบความสัมพันธ์แบบผกผันในภายหลังนั้นค่อนข้างง่าย


24

คำถามที่ดีกว่าคือ "มีเหตุผลที่จะไม่ตรงกันข้าม" หรือไม่? แกนข้อมูลเป็นกรอบการจัดการกราฟวัตถุจริง ๆ ไม่ใช่กรอบการคงอยู่ กล่าวอีกนัยหนึ่งหน้าที่ของมันคือการจัดการความสัมพันธ์ระหว่างวัตถุในกราฟวัตถุ ความสัมพันธ์ผกผันทำให้เรื่องนี้มากได้ง่ายขึ้น ด้วยเหตุผลดังกล่าว Core Data คาดว่าความสัมพันธ์แบบผกผันและถูกเขียนขึ้นสำหรับกรณีการใช้งานนั้น หากไม่มีพวกเขาคุณจะต้องจัดการความสอดคล้องกราฟวัตถุด้วยตัวเอง โดยเฉพาะอย่างยิ่งความสัมพันธ์ต่อหลาย ๆ คนที่ไม่มีความสัมพันธ์แบบผกผันมีความเป็นไปได้สูงที่ Core Data เสียหายเว้นแต่คุณจะทำงานหนักมากเพื่อให้สิ่งต่าง ๆ ทำงานได้ ค่าใช้จ่ายในแง่ของขนาดดิสก์สำหรับความสัมพันธ์ผกผันจริงๆไม่มีนัยสำคัญเมื่อเทียบกับผลประโยชน์ที่ได้รับคุณ


20

มีอย่างน้อยหนึ่งสถานการณ์ที่สามารถสร้างเคสที่ดีสำหรับความสัมพันธ์ของข้อมูลหลักโดยไม่ต้องผกผัน: เมื่อมีความสัมพันธ์ของข้อมูลหลักอื่นระหว่างวัตถุทั้งสองอยู่แล้วซึ่งจะจัดการการบำรุงรักษากราฟวัตถุ

ตัวอย่างเช่นหนังสือมีหลายหน้าในขณะที่หน้าอยู่ในหนังสือเล่มเดียว นี่เป็นความสัมพันธ์แบบสองทางต่อหลายคน การลบหน้าเพียงลบล้างความสัมพันธ์ในขณะที่การลบหนังสือจะเป็นการลบหน้านั้นด้วย

อย่างไรก็ตามคุณอาจต้องการติดตามหน้าปัจจุบันที่กำลังอ่านสำหรับหนังสือแต่ละเล่ม สิ่งนี้สามารถทำได้ด้วยคุณสมบัติ "currentPage" บนหน้าแต่จากนั้นคุณต้องใช้ตรรกะอื่น ๆ เพื่อให้แน่ใจว่ามีการทำเครื่องหมายหน้าเดียวในหนังสือเป็นหน้าปัจจุบันได้ตลอดเวลา แต่การสร้างความสัมพันธ์ในปัจจุบันของเพจจากหนังสือไปยังหน้าเดียวจะทำให้แน่ใจได้ว่าจะมีการทำเครื่องหมายหน้าเว็บปัจจุบันเพียงหน้าเดียวเสมอไปและนอกจากนั้นหน้านี้สามารถเข้าถึงได้ง่ายด้วยการอ้างอิงถึงหนังสือด้วย book.currentPage

การนำเสนอกราฟิกของความสัมพันธ์ข้อมูลหลักระหว่างหนังสือและหน้า

ความสัมพันธ์ซึ่งกันและกันจะเป็นอย่างไรในกรณีนี้ สิ่งที่ไร้สาระส่วนใหญ่ "myBook" หรือคล้ายกันสามารถเพิ่มกลับไปในทิศทางอื่น ๆ แต่มันมีเพียงข้อมูลที่มีอยู่แล้วในความสัมพันธ์ "หนังสือ" สำหรับหน้าและเพื่อสร้างความเสี่ยงของตัวเอง ในอนาคตอาจมีการเปลี่ยนแปลงวิธีการที่คุณใช้หนึ่งในความสัมพันธ์เหล่านี้ส่งผลให้เกิดการเปลี่ยนแปลงในการกำหนดค่าข้อมูลหลักของคุณ หากมีการใช้ page.myBook ในบางแห่งที่ควรใช้ page.book ในรหัสอาจมีปัญหาได้ อีกวิธีหนึ่งในการหลีกเลี่ยงในเชิงรุกคือการไม่เปิดเผย myBook ในคลาสย่อย NSManagedObject ที่ใช้ในการเข้าถึงหน้า อย่างไรก็ตามมันสามารถเป็นที่ถกเถียงกันอยู่ว่ามันง่ายกว่าที่จะไม่สร้างแบบจำลองผกผันตั้งแต่แรก

ในตัวอย่างที่ระบุไว้กฎการลบสำหรับความสัมพันธ์หน้าปัจจุบันควรถูกตั้งค่าเป็น "ไม่ดำเนินการ" หรือ "เรียงซ้อน" เนื่องจากไม่มีความสัมพันธ์ซึ่งกันและกันเป็น "ลบล้าง" (น้ำตกหมายความว่าคุณกำลังฉีกทุกหน้าออกจากหนังสือเมื่อคุณอ่าน แต่อาจเป็นเรื่องจริงถ้าคุณเป็นหวัดและต้องการน้ำมัน)

เมื่อสามารถแสดงให้เห็นว่าความสมบูรณ์ของกราฟวัตถุนั้นไม่ได้มีความเสี่ยงเช่นในตัวอย่างนี้และความซับซ้อนของรหัสและความสามารถในการบำรุงรักษาได้รับการปรับปรุงให้ดีขึ้นอาจเป็นที่ถกเถียงกันว่าความสัมพันธ์ที่ไม่มีผกผันอาจเป็นการตัดสินใจที่ถูกต้อง


ขอบคุณ Duncan - มันใกล้เคียงกับกรณีการใช้งานที่ฉันมี โดยพื้นฐานแล้วฉันต้องได้รับหน้าสุดท้ายของหนังสือ ฉันต้องการสิ่งนี้เพื่อเป็นค่ายืนยันเพื่อให้ฉันสามารถใช้ในการสรุปการเรียก ฉันได้ตั้งค่าการผกผัน "bookIAmLastPageOf" แต่มันไร้สาระมากและทำให้เกิดปัญหาอื่น ๆ (ฉันไม่เข้าใจอย่างถูกต้อง) คุณรู้หรือไม่ว่ามีวิธีการปิดการเตือนสำหรับกรณีเดียวหรือไม่?
Benjohn

มีวิธีการปิดการใช้งานคำเตือนหรือไม่? ตอนนี้ผมมี 2: ... ควรมีผกผันและไม่มีการดำเนินการลบกฎ ... อาจส่งผลให้ความสัมพันธ์กับวัตถุที่ถูกลบ และสามารถcurrentPageทำเครื่องหมายว่าOptional?
SwiftArchitect

การจัดเก็บ currentPage เป็น NSManagedObjectID แทนที่จะเป็นความสัมพันธ์เป็นแนวทางที่ถูกต้องหรือไม่
user965972

4

ในขณะที่เอกสารไม่ต้องการการผกผัน แต่ฉันเพิ่งแก้ไขสถานการณ์ที่จริงแล้วส่งผลให้ "การสูญเสียข้อมูล" โดยไม่มีการย้อนกลับ ฉันมีวัตถุรายงานที่มีความสัมพันธ์กับวัตถุที่รายงานได้จำนวนมาก หากไม่มีความสัมพันธ์แบบผกผันการเปลี่ยนแปลงใด ๆ กับความสัมพันธ์แบบหลายต่อหลายคนจะสูญหายไปเมื่อเปิดใหม่ หลังจากตรวจสอบการดีบักข้อมูลหลักเป็นที่ชัดเจนว่าแม้ว่าฉันจะบันทึกวัตถุรายงานการปรับปรุงกราฟวัตถุ (ความสัมพันธ์) ก็ไม่เคยทำ ฉันเพิ่มสิ่งที่ตรงกันข้ามแม้ว่าฉันจะไม่ได้ใช้และ voila ก็ใช้ได้ ดังนั้นจึงอาจไม่บอกว่าจำเป็น แต่ความสัมพันธ์ที่ไม่มีผู้รุกรานสามารถมีผลข้างเคียงที่แปลกได้อย่างแน่นอน


0

ผู้ใช้ยังใช้เพื่อObject Integrityเหตุผลอื่น ๆ ด้วย (ดูเหตุผลอื่น ๆ ดูคำตอบอื่น ๆ ):

วิธีที่แนะนำคือการสร้างแบบจำลองความสัมพันธ์ในทั้งสองทิศทางและระบุความสัมพันธ์ผกผันอย่างเหมาะสม ข้อมูลหลักใช้ข้อมูลนี้เพื่อรับรองความสอดคล้องของกราฟวัตถุหากมีการเปลี่ยนแปลง

จาก: 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.