Каждое ли базовое отношение данных должно иметь обратную сторону? - PullRequest
144 голосов
/ 19 апреля 2009

Допустим, у меня есть два класса сущностей: SocialApp и SocialAppType

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

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

Пункт назначения отношения SocialApp type представляет собой одну запись в SocialAppType.

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

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

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

Нужно ли обратное и зачем?

Ответы [ 7 ]

129 голосов
/ 03 июля 2013

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

Предположим, вы смоделировали это следующим образом: enter image description here

Обратите внимание, что у вас есть отношение к одному , которое называется " type ", от 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 is 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];
111 голосов
/ 19 апреля 2009

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

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

- Cocoa Dev Central

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

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

46 голосов
/ 24 июля 2010

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

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

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

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

24 голосов
/ 21 апреля 2009

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

20 голосов
/ 31 января 2015

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

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

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

Graphical presentation of core data relationship between books and pages

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

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

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

4 голосов
/ 07 февраля 2015

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

0 голосов
/ 15 февраля 2019

Инверсы также используются для Object Integrity (по другим причинам, см. Другие ответы):

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

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

Приведенная ссылка дает вам идеи, почему вы должны иметь набор inverse. Без этого вы можете потерять данные / целостность. Кроме того, вероятность того, что вы получите доступ к объекту nil, более вероятна.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...