Должно ли каждое отношение данных к Core Data иметь обратное?

Предположим, у меня есть два classа Entity: SocialApp и SocialAppType

В SocialApp меня есть один атрибут: appURL и одно отношение: type .

В SocialAppType меня есть три атрибута: baseURL , name и favicon .

SocialApp type отношений SocialApp – это одна запись в SocialAppType .

Например, для нескольких учетных записей Flickr будет SocialApp записей SocialApp , причем каждая запись содержит ссылку на учетную запись человека. Для типа «Flickr» будет одна запись SocialAppType , на которую SocialApp все записи SocialApp .

Когда я создаю приложение с этой схемой, я получаю предупреждение о том, что нет обратных отношений между SocialAppType и SocialApp .

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

Нужен ли мне обратный и почему?

На практике у меня не было никаких потерь данных из-за отсутствия обратного – по крайней мере, я знаю. Быстрый Google предлагает вам использовать их:

Обратная связь не просто делает вещи более аккуратными, а фактически используется Core Data для обеспечения целостности данных.

– Cocoa Dev Central

Обычно вы должны моделировать отношения в обоих направлениях и соответствующим образом определять обратные отношения. Основные данные используют эту информацию для обеспечения согласованности графиков объектов, если они сделаны (см. «Манипулирование отношениями и целостность графика объектов»). Для обсуждения некоторых причин, по которым вы можете не моделировать отношения в обоих направлениях, а также некоторые из проблем, которые могут возникнуть, если вы этого не сделаете, см. «Однонаправленные отношения».

– Руководство по программированию основных данных

Документация Apple имеет прекрасный пример, который предлагает ситуацию, когда у вас могут быть проблемы, не имея обратной связи. Давайте сопоставим его в этом случае.

Предположим, вы смоделировали его следующим образом: введите описание изображения здесь

Обратите внимание, что у вас есть одно отношение, называемое « тип », от SocialApp до SocialAppType . Связь не является необязательной и имеет правило удаления «deny» .

Теперь рассмотрим следующее:

 SocialApp *socialApp; SocialAppType *appType; // assume entity instances correctly instantiated [socialApp setSocialAppType:appType]; [managedObjectContext deleteObject:appType]; BOOL saved = [managedObjectContext save:&error]; 

Мы ожидаем, что этот контекст не сработает, поскольку мы установили правило удаления как Deny, а отношение не является необязательным.

Но здесь спасение преуспевает.

Причина в том, что мы не установили обратную связь . Из-за этого экземпляр socialApp не становится помеченным как измененный при удалении appType. Таким образом, для socialApp не требуется проверки, прежде чем сохранять (он не требует проверки, поскольку никаких изменений не произошло). Но на самом деле произошло изменение. Но это не отражается.

Если мы вспомним appType by

 SocialAppType *appType = [socialApp socialAppType]; 

appType – нуль.

Странно, не так ли? Мы получаем 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]; 

Я перефразирую окончательный ответ, который я нашел в More iPhone 3 Development от Дейва Марка и Джеффа ЛеМарче.

Apple обычно рекомендует, чтобы вы всегда создавали и указывали обратное, даже если вы не используете обратную связь в своем приложении. По этой причине он предупреждает вас, когда вы не можете обеспечить обратное.

Отношения не обязательно должны иметь обратный, поскольку существует несколько сценариев, в которых обратная связь может повредить производительность. Например, предположим, что обратная связь содержит чрезвычайно большое количество объектов. Удаление инверсии требует итерации над множеством, которое представляет собой обратную, ослабляющую производительность.

Но если у вас нет определенной причины, не следует моделировать инверсию . Это помогает Core Data обеспечивать целостность данных. Если вы столкнулись с проблемами производительности, относительно легко удалить обратную связь позже.

Лучший вопрос: «есть ли причина не иметь обратного»? Основные данные – это действительно структура управления графами объектов, а не система персистентности. Другими словами, его задача – управлять отношениями между объектами в графе объектов. Обратные отношения делают это намного проще. По этой причине Core Data ожидает обратные отношения и написана для этого случая использования. Без них вам придется самостоятельно управлять контурами объектов. В частности, к-многим без обратной связи, очень вероятно, будут повреждены Core Data , если вы работаете очень трудно держать вещи работать. Стоимость с точки зрения размера диска для обратных отношений действительно незначительна по сравнению с выгодой, которую она вам приносит.

Существует, по крайней мере, один сценарий, в котором может быть сделан хороший случай для отношения данных ядра без обратного: когда есть еще одна взаимосвязь данных ядра между этими двумя объектами, которая будет обрабатывать сохранение графа объекта.

Например, книга содержит много страниц, а страница – в одной книге. Это двусторонние отношения «много-к-одному». Удаление страницы просто сводит на нет отношения, тогда как удаление книги также приведет к удалению страницы.

Однако вы также можете отслеживать текущую страницу, просматриваемую для каждой книги. Это можно сделать с помощью свойства currentPage на странице , но тогда вам понадобится другая логика, чтобы в любой момент пометить как одну страницу в книге как текущую страницу. Вместо этого, если отношение currentPage от книги к одной странице будет гарантировать, что всегда будет отображаться только одна текущая страница, и, кроме того, эта страница может быть легко доступна с ссылкой на книгу с помощью book.currentPage.

Графическое представление взаимосвязей между данными между книгами и страницами

Каковы будут взаимные отношения в этом случае? Что-то в значительной степени бессмысленно. «myBook» или подобное может быть добавлено обратно в другом направлении, но в нем содержится только информация, уже содержащаяся в отношении «книги» для страницы, и поэтому создает свои собственные риски. Возможно, в будущем изменится способ использования одного из этих отношений, что приведет к изменениям в вашей конфигурации основных данных. Если page.myBook использовался в некоторых местах, где page.book должен был использоваться в коде, могут возникнуть проблемы. Другой способ упредить это можно было бы также не подвергать myBook в подclassе NSManagedObject, который используется для доступа к странице. Однако можно утверждать, что проще не моделировать обратное в первую очередь.

В приведенном примере правило удаления для отношения currentPage должно быть установлено на «No Action» или «Cascade», так как нет взаимного отношения к «Nullify». (Каскад подразумевает, что вы вырываете каждую страницу из книги, когда читаете ее, но это может быть правдой, если вы особенно холодны и нуждаетесь в топливе.)

Когда можно продемонстрировать, что целостность графа объектов не подвержена риску, как в этом примере, а также улучшена сложность кода и ремонтопригодность, можно утверждать, что отношение без инверсного может быть правильным решением.

Хотя документы, похоже, не требуют обратного, я просто решил сценарий, который фактически привел к «потере данных», не имея обратного. У меня есть объект отчета, который имеет отношение «многие» к отчетным объектам. Без обратной зависимости любые изменения отношения ко многим были потеряны после перезапуска. После проверки отладки основных данных было очевидно, что, хотя я сохранял объект отчета, обновления графиков объектов (отношений) никогда не выполнялись. Я добавил инверсию, хотя я ее не использую, и вуаля, она работает. Поэтому он может не сказать, что это необходимо, но отношения без инверсий могут иметь странные побочные эффекты.

Давайте будем гением компьютера.