objective-c - هل يجب أن يكون لكل علاقة بيانات أساسية معكوس؟




core-data (6)

السؤال الأفضل هو ، "هل هناك سبب لعدم وجود معكوس"؟ البيانات الأساسية هي حقا إطار إدارة الرسم البياني الكائن ، وليس إطار استمرار. وبعبارة أخرى ، وظيفتها هي إدارة العلاقات بين الكائنات في الرسم البياني الكائن. العلاقات العكسية تجعل هذا أسهل بكثير . لهذا السبب ، تتوقع Core Data علاقات معكوسة ويتم كتابتها لحالة الاستخدام هذه. بدونهم ، سيكون عليك إدارة اتساق الرسم البياني الكائن بنفسك. على وجه الخصوص ، من المحتمل جدًا أن تتلف البيانات الأساسية إلى العديد من العلاقات دون علاقة عكسية ، إلا إذا عملت بجد للحفاظ على عمل الأشياء. التكلفة من حيث حجم القرص للعلاقات العكسية هي في الحقيقة غير ذات أهمية بالمقارنة مع الفائدة التي تكتسبها.

لنفترض أن لدي فئتين من الكيانات: SocialApp و SocialAppType

في SocialApp لدي سمة واحدة: appURL واحدة: type .

في SocialAppType لدي ثلاث سمات: baseURL ، name و favicon .

وجهة type العلاقة SocialApp هو سجل واحد في SocialAppType .

على سبيل المثال ، بالنسبة لحسابات Flickr المتعددة ، سيكون هناك عدد من سجلات SocialApp ، مع كل سجل يحمل رابطًا إلى حساب الشخص. سيكون هناك سجل SocialAppType واحد SocialAppType "Flickr" ، الذي SocialApp جميع سجلات SocialApp .

عندما أقوم بإنشاء تطبيق باستخدام هذا المخطط ، أحصل على تحذير بعدم وجود علاقة عكسية بين SocialAppType و SocialApp .

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

هل أحتاج إلى معكوس ، ولماذا؟


تحتوي وثائق 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];

في الواقع ، لم يكن لدي أي فقدان للبيانات بسبب عدم وجود معكوس - على الأقل أنا على علم بذلك. تقترح Google سريعة عليك استخدامها:

العلاقة العكسية لا تجعل الأشياء أكثر مرتبة فحسب ، بل تستخدمها Core Data للحفاظ على سلامة البيانات.

- الكاكاو ديف الوسطى

يجب عليك نموذج العلاقات في كلا الاتجاهين ، وتحديد العلاقات العكسية بشكل مناسب. تستخدم البيانات الأساسية هذه المعلومات لضمان تناسق الرسم البياني للكائنات إذا تم إجراء تغيير (راجع "معالجة العلاقات ونزاهة الرسم البياني للأشياء"). لمناقشة بعض الأسباب التي قد تدفعك إلى عدم وضع نموذج لعلاقة في كلا الاتجاهين ، وبعض المشكلات التي قد تنشأ إذا لم تقم بذلك ، راجع "العلاقات أحادية الاتجاه".

- دليل برمجة البيانات الأساسية


في حين لا يبدو أن المستندات تتطلب معكوسًا ، فقد قمت للتو بحل سيناريو أدى في الواقع إلى "فقدان البيانات" من خلال عدم وجود معكوس. لدي كائن تقرير يحتوي على علاقة متعددة الأطراف على كائنات قابلة للإبلاغ عنها. بدون العلاقة العكسية ، يتم فقدان أي تغييرات في العلاقة العديدة عند إعادة التشغيل. بعد فحص تصحيح البيانات الأساسية ، كان واضحًا أنه على الرغم من أنني كنت أقوم بحفظ كائن التقرير ، فإن التحديثات على الرسم البياني للكائن (العلاقات) لم يتم إنشاؤها أبدًا. أضفت معكوسًا ، على الرغم من أنني لا أستخدمه ، وفويلا ، فإنه يعمل. لذلك قد لا يكون الأمر مطلوبًا ، ولكن العلاقات بدون عكوس يمكن أن يكون لها آثار جانبية غريبة بالتأكيد.


سأعيد صياغة الإجابة النهائية التي وجدتها في المزيد من تطوير iPhone 3 بواسطة Dave Mark و Jeff LeMarche.

توصي Apple بشكل عام بأن تقوم دائمًا بإنشاء وتحديد معكوس ، حتى إذا لم تستخدم العلاقة العكسية في تطبيقك. لهذا السبب ، يحذرك عندما تخفق في توفير معكوس.

لا يُشترط أن تكون العلاقات معكوسة ، لأن هناك بعض السيناريوهات التي يمكن للعلاقة العكسية أن تؤذي الأداء. على سبيل المثال ، افترض أن العلاقة المعكوسة تحتوي على عدد كبير جدًا من الكائنات. تتطلب إزالة المعكوس تكرارًا على المجموعة التي تمثل معكوسًا ، مما يؤدي إلى إضعاف الأداء.

ولكن ما لم يكن لديك سبب محدد لعدم القيام بذلك ، فقم بتجميع النموذج العكسي . يساعد Core Data على تكامل البيانات. إذا واجهت مشكلات في الأداء ، فمن السهل نسبياً إزالة العلاقة العكسية فيما بعد.


لا تتصل أبدًا بـ [super valueForKey: ..] في فئة فرعية NSManagedObject! (إلا إذا قمت بتنفيذها في الطبقة الفائقة بنفسك) وبدلاً من ذلك استخدم أساليب الموصل البدائي.

نموذج تنفيذ getter / setter من ADC :

@interface Department : NSManagedObject
@property(nonatomic, strong) NSString *name;
@end

@interface Department (PrimitiveAccessors)
- (NSString *)primitiveName;
- (void)setPrimitiveName:(NSString *)newName;
@end


@implementation Department

@dynamic name;

- (NSString *)name
{
    [self willAccessValueForKey:@"name"];
    NSString *myName = [self primitiveName];
    [self didAccessValueForKey:@"name"];
    return myName;
}

- (void)setName:(NSString *)newName
{
    [self willChangeValueForKey:@"name"];
    [self setPrimitiveName:newName];
    [self didChangeValueForKey:@"name"];
}

@end




objective-c core-data