Чи має кожне базове відношення даних мати обернене?


150

Скажімо, у мене є два навчальні класи: SocialAppіSocialAppType

В У SocialAppмене є один атрибут: appURLі одне відношення: type.

В У SocialAppTypeмене є три атрибута: baseURL, nameі favicon.

Призначення SocialAppвідносин type- це один запис у SocialAppType.

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

Коли я будую додаток із цією схемою, я отримую попередження про відсутність зворотного зв'язку між SocialAppTypeта SocialApp.

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

Чи потрібна мені обернена, і навіщо?

Відповіді:


117

На практиці у мене не було жодної втрати даних через відсутність обернення - принаймні, про те, що я знаю. Швидкий Google пропонує вам скористатися ними:

Зворотна залежність не просто робить речі більш охайними, вона фактично використовується Core Data для підтримки цілісності даних.

- Какао Дев Центральний

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

- Основний посібник з програмування даних


5
Дивіться відповідь MadNik (внизу сторінки в момент, коли я це пишу) для більш ретельного пояснення того, що означають документи, коли вони говорять, що обернені зв’язки допомагають підтримувати цілісність даних.
Марк Амері

135

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

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

Зауважте, у вас є відносини до одного, що називається " тип ", від SocialAppдо SocialAppType. Зв'язок не є необов'язковим і має правило видалення "заборонити" .

Тепер розглянемо наступне:

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

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

Ми очікуємо, що не вдасться зберегти цей контекст, оскільки ми встановили правило видалення як Заборонити, тоді як відносини необов’язкові.

Але ось зберегти це вдається.

Причина в тому, що ми не встановили зворотних відносин . Через це при видаленні appType екземпляр socialApp не позначається як змінений. Отже, перед збереженням не відбувається перевірка для 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
Це чудова відповідь; дякую, що чітко проаналізував, що є - від документів і з усього, що я прочитав - головний аргумент на користь наявності зворотних зв'язків для всього, навіть коли обернені стосунки не мають людського значення. Це дійсно повинно бути прийнятою відповіддю. Весь цей потік питання відсутній зараз - це більш детальне вивчення причин, через які ви можете не мати зворотних зворотів, зачіпаних у відповіді Роуз Перроне (а також у документації, небагато).
Марк Амері

46

Я перефразую остаточну відповідь, яку я знайшов у « Додатковій розробці iPhone 3» Дейвом Марком та Джефом Лемарше.

Як правило, Apple рекомендує завжди створювати та вказувати зворотні, навіть якщо ви не використовуєте зворотну залежність у вашому додатку. З цієї причини він попереджає вас, коли ви не можете надати зворотну сторону.

Зв'язки не повинні мати зворотного, оскільки є кілька сценаріїв, за яких зворотна залежність може зашкодити роботі. Наприклад, припустимо, що зворотна залежність містить надзвичайно велику кількість об'єктів. Видалення оберненого вимагає повторного набору, що представляє собою зворотну, послаблюючий працездатність.

Але якщо у вас немає конкретних причин цього не робити, моделюйте зворотне . Це допомагає Core Data забезпечити цілісність даних. Якщо у вас виникли проблеми з продуктивністю, пізніше вилучити зворотну залежність порівняно легко.


24

Краще питання: "чи є причина не мати зворотного"? Основні дані дійсно є рамкою управління об'єктним графіком, а не рамкою стійкості. Іншими словами, його завдання полягає в управлінні взаємозв’язками між об'єктами в графіку об'єкта. Зворотні стосунки роблять це набагато простіше. З цієї причини Core Data очікує зворотних зв’язків і записується для цього випадку використання. Без них вам доведеться самостійно керувати послідовністю графіка об'єкта. Зокрема, дуже багато стосунків без зворотних зв'язків, швидше за все, можуть бути пошкоджені Основними даними, якщо ви не дуже працюєте, щоб продовжувати працювати. Вартість з точки зору розміру диска для зворотних зв'язків дійсно незначна порівняно з вигодою, яку він отримує від вас.


20

Існує щонайменше один сценарій, коли можна зробити хороший випадок для взаємозв'язку основних даних без зворотного: коли між двома об'єктами вже є інше співвідношення основних даних, яке буде обробляти підтримку графіку об'єкта.

Наприклад, книга містить багато сторінок, а сторінка - в одній. Це двосторонні стосунки багато в одному. Видалення сторінки просто анулює відносини, тоді як видалення книги також видалить сторінку.

Однак ви також можете відстежити поточну сторінку, яку читають для кожної книги. Це може бути зроблено за допомогою «CurrentPage» власності на сторінці , але тоді вам потрібно інша логіка , щоб гарантувати , що тільки одна сторінки в книзі позначена як поточна сторінка в будь-який час. Натомість, встановлення поточного сторінкового зв’язку з Книги на одну сторінку гарантуватиме, що завжди буде лише одна поточна сторінка, а також, що до цієї сторінки можна легко отримати доступ із посиланням на книгу просто book.currentPage.

Графічне представлення взаємозв'язку основних даних між книгами та сторінками

Якими були б взаємні відносини в цьому випадку? Щось багато в чому безглузде. "myBook" або подібне можна додати ще в іншому напрямку, але воно містить лише ту інформацію, яка вже міститься у відносинах "книга" для сторінки, і тому створює власні ризики. Можливо, в майбутньому спосіб використання одного з цих відносин буде змінено, що призведе до змін у вашій конфігурації основних даних. Якщо page.myBook використовувався в деяких місцях, де page.book повинен був використовуватися в коді, можуть виникнути проблеми. Інший спосіб проактивного уникнення цього полягав би також у тому, щоб не виставляти MyBook у підкласі NSManagedObject, який використовується для доступу до сторінки. Однак можна стверджувати, що простіше не моделювати інверс в першу чергу.

У наведеному прикладі правило видалення для поточного відносини сторінки повинно бути встановлено на "Без дії" або "Каскад", оскільки немає взаємного відношення до "Звести нанівець". (Каскад означає, що ви вириваєте кожну сторінку з книги під час її читання, але це може бути правдою, якщо вам особливо холодно і потрібно паливо.)

Коли можна продемонструвати, що цілісність об’єктних графіків не загрожує, як у цьому прикладі, і складність коду та ремонтопридатність вдосконалюються, можна стверджувати, що відносини без оберненого можуть бути правильним рішенням.


Дякую, Дункан - це надзвичайно близько до випадків використання у мене. По суті, мені потрібно мати можливість отримати останню сторінку книги. Мені потрібно, щоб це було збереженим значенням, щоб я міг використовувати його в предикаті для отримання. Я створив зворотний "bookIAmLastPageOf", але це досить безглуздо і викликає інші проблеми (я не правильно розумію). Чи знаєте ви, чи є спосіб відключити попередження для одного випадку?
Бенджон

Чи є спосіб відключити попередження? Тепер у мене є 2: ... повинно бути зворотне, і Правило видалення без дії ... може призвести до відносин до видалених об'єктів . І можна currentPageпозначити як Optional?
SwiftArchitect

Чи зберігання поточної сторінки як NSManagedObjectID замість відносин є коректним підходом?
користувач965972

4

У той час як документи, здається, не вимагають зворотного, я просто вирішив сценарій, який насправді призвів до "втрати даних", не маючи зворотного. У мене є об’єкт звіту, який має відношення до багатьох об'єктів, що репортажуються. Без зворотного відношення будь-які зміни у відношенні до багатьох втрачалися при повторному запуску. Після огляду налагодження Core Data було очевидно, що, хоча я і зберігав об’єкт звіту, оновлення до об'єктного графіка (відносини) ніколи не проводилися. Я додав обернену, хоча я не використовую її, і вуаля, вона працює. Тож може не сказати, що це потрібно, але стосунки без зворотних дій напевно можуть мати дивні побічні ефекти.


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

Взагалі немає потреби в зворотному взаємозв'язку. Але є кілька химерностей / помилок у даних Core, де вам потрібна зворотна залежність. Бувають випадки, коли зв’язки / об'єкти пропадають, хоча помилки контексту не зберігаються, якщо відсутні взаємні зв'язки. Перевірте цей приклад , який я створив для демонстрації відсутніх об'єктів та способів їх вирішення під час роботи з Core data

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.