Powiedzmy, że mam dwie klasy Entity: SocialApp
iSocialAppType
W SocialApp
mam jeden atrybut: appURL
i jedno Stan: type
.
W SocialAppType
Mam trzy atrybuty: baseURL
, name
i favicon
.
Miejsce docelowe SocialApp
relacji type
to pojedynczy rekord w SocialAppType
.
Na przykład w przypadku wielu kont Flickr byłoby kilka SocialApp
rekordów, z których każdy zawiera łącze do konta danej osoby. Byłby jeden SocialAppType
rekord typu „Flickr”, na który SocialApp
wskazywałyby wszystkie rekordy.
Kiedy tworzę aplikację z tym schematem, otrzymuję ostrzeżenie, że nie ma odwrotnej relacji między SocialAppType
i SocialApp
.
/Users/username/Developer/objc/TestApp/TestApp.xcdatamodel:SocialApp.type: warning: SocialApp.type -- relationship does not have an inverse
Czy potrzebuję odwrotności i dlaczego?
źródło
Dokumentacja Apple zawiera świetny przykład, który sugeruje sytuację, w której możesz mieć problemy, nie mając odwrotnej zależności. Zmapujmy to w tym przypadku.
Załóżmy, że zaprojektowałeś to w następujący sposób:
Zauważ, że istnieje relacja do jednego zwana „ typem ”, od
SocialApp
doSocialAppType
. Relacja nie jest opcjonalna i ma regułę usuwania „odmów” .Rozważmy teraz następujące kwestie:
Oczekujemy, że ten kontekst nie zostanie zapisany, ponieważ ustawiliśmy regułę usuwania jako Odmów, podczas gdy relacja nie jest opcjonalna.
Ale tutaj zapis się udaje.
Powodem jest to, że nie ustawiliśmy odwrotnej zależności . Z tego powodu instancja aplikacji społecznościowej nie jest oznaczana jako zmieniona po usunięciu appType. Dlatego przed zapisaniem aplikacji społecznościowej nie jest przeprowadzana weryfikacja (zakłada ona, że nie jest wymagana weryfikacja, ponieważ nie nastąpiła żadna zmiana). Ale tak naprawdę nastąpiła zmiana. Ale to się nie odbija.
Jeśli przypomnimy sobie appType według
appType ma wartość nil.
Dziwne, prawda? Otrzymujemy zero dla atrybutu nie opcjonalnego?
Więc nie masz kłopotów, jeśli ustawiłeś odwrotną zależność. W przeciwnym razie musisz wymusić walidację, pisząc kod w następujący sposób.
źródło
Sparafrazuję ostateczną odpowiedź, którą znalazłem w More iPhone 3 Development autorstwa Dave'a Marka i Jeffa LeMarche.
Firma Apple ogólnie zaleca, aby zawsze tworzyć i określać odwrotność, nawet jeśli nie używasz odwrotnej relacji w swojej aplikacji. Z tego powodu ostrzega Cię, gdy nie podasz odwrotności.
Relacje nie muszą mieć odwrotności, ponieważ istnieje kilka scenariuszy, w których odwrotna zależność może zaszkodzić wydajności. Na przykład załóżmy, że odwrotna zależność zawiera niezwykle dużą liczbę obiektów. Usunięcie odwrotności wymaga iteracji po zestawie, który reprezentuje odwrotność, osłabiającą wydajność.
Ale jeśli nie masz konkretnego powodu, aby tego nie robić, modeluj odwrotnie . Pomaga Core Data w zapewnieniu integralności danych. Jeśli napotkasz problemy z wydajnością, stosunkowo łatwo jest później usunąć odwrotną zależność.
źródło
Lepsze pytanie brzmi: „czy istnieje powód, aby nie mieć odwrotności”? Dane podstawowe to w rzeczywistości struktura zarządzania grafami obiektów, a nie struktura trwałości. Innymi słowy, jego zadaniem jest zarządzanie relacjami między obiektami na grafie obiektów. Odwrotne relacje znacznie to ułatwiają. Z tego powodu Core Data oczekuje odwrotnych relacji i jest napisany dla tego przypadku użycia. Bez nich będziesz musiał samodzielnie zarządzać spójnością grafu obiektów. W szczególności relacje typu „to-many” bez relacji odwrotnej są bardzo prawdopodobne, że zostaną uszkodzone przez dane podstawowe, chyba że będziesz bardzo ciężko pracować, aby wszystko działało. Koszt pod względem rozmiaru dysku dla odwrotnych relacji jest naprawdę nieistotny w porównaniu z korzyściami, jakie przynosi.
źródło
Istnieje co najmniej jeden scenariusz, w którym można przedstawić dobre argumenty za podstawową relacją danych bez odwrotności: gdy istnieje już inna podstawowa relacja danych między dwoma obiektami, która zajmie się utrzymaniem grafu obiektu.
Na przykład książka zawiera wiele stron, podczas gdy strona znajduje się w jednej książce. Jest to dwukierunkowa relacja wiele do jednego. Usunięcie strony po prostu unieważnia relację, podczas gdy usunięcie książki spowoduje również usunięcie strony.
Możesz jednak również chcieć śledzić aktualnie czytaną stronę dla każdej książki. Można to zrobić za pomocą właściwości „currentPage” na stronie , ale wtedy potrzebna jest inna logika, aby zapewnić, że tylko jedna strona w książce jest oznaczona jako bieżąca strona w dowolnym momencie. Zamiast tego, utworzenie relacji currentPage z Book na pojedynczą stronę zapewni, że zawsze będzie zaznaczona tylko jedna bieżąca strona, a ponadto, że ta strona będzie łatwo dostępna z odniesieniem do książki po prostu book.currentPage.
Jaka byłaby w tym przypadku wzajemna relacja? Coś w dużej mierze bezsensownego. „myBook” lub coś podobnego można dodać z powrotem w innym kierunku, ale zawiera on tylko informacje zawarte już w relacji „książka” dla strony, co stwarza własne ryzyko. Być może w przyszłości sposób korzystania z jednej z tych relacji ulegnie zmianie, co spowoduje zmiany w konfiguracji podstawowych danych. Jeśli page.myBook został użyty w niektórych miejscach, w których w kodzie powinien zostać użyty page.book, mogą wystąpić problemy. Innym sposobem proaktywnego uniknięcia tego byłoby również nie ujawnianie myBook w podklasie NSManagedObject, która jest używana do uzyskiwania dostępu do strony. Można jednak argumentować, że w pierwszej kolejności łatwiej jest nie modelować odwrotności.
W przedstawionym przykładzie reguła usuwania dla relacji currentPage powinna być ustawiona na „No Action” lub „Cascade”, ponieważ nie ma wzajemnego związku z „Nullify”. (Kaskada sugeruje, że podczas czytania wyrywasz każdą stronę z książki, ale może to być prawda, jeśli jesteś szczególnie zimny i potrzebujesz paliwa).
Kiedy można wykazać, że integralność grafu obiektowego nie jest zagrożona, jak w tym przykładzie, a złożoność kodu i łatwość konserwacji są poprawione, można argumentować, że relacja bez odwrotności może być właściwą decyzją.
źródło
currentPage
oznaczyć jakoOptional
?Chociaż dokumenty nie wydają się wymagać odwrotności, właśnie rozwiązałem scenariusz, który w rzeczywistości spowodował „utratę danych”, ponieważ nie miał odwrotności. Mam obiekt raportu, który ma relację do wielu na obiektach raportowanych. Bez relacji odwrotnej wszelkie zmiany w relacji „wiele do wielu” zostały utracone po ponownym uruchomieniu. Po sprawdzeniu debugowania danych podstawowych okazało się, że mimo zapisywania obiektu raportu aktualizacje wykresu obiektu (relacji) nigdy nie były wykonywane. Dodałem odwrotność, mimo że go nie używam i voila, działa. Może więc nie mówić, że jest to wymagane, ale relacje bez odwrotności mogą z pewnością mieć dziwne skutki uboczne.
źródło
Odwrotności są również używane do
Object Integrity
(z innych powodów zobacz inne odpowiedzi):Od: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreData/HowManagedObjectsarerelated.html#//apple_ref/doc/uid/TP40001075-CH17-SW1
Podany link daje pomysły, dlaczego warto mieć
inverse
zestaw. Bez tego możesz stracić dane / integralność. Ponadto prawdopodobieństwo uzyskania dostępu do obiektunil
jest bardziej prawdopodobne.źródło
Generalnie nie ma potrzeby stosowania odwrotnej zależności. Ale jest kilka dziwactw / błędów w danych podstawowych, w których potrzebujesz odwrotnej relacji. Istnieją przypadki, w których brakuje relacji / obiektów, nawet jeśli nie ma błędu podczas zapisywania kontekstu, jeśli brakuje odwrotnej relacji. Sprawdź ten przykład , który utworzyłem, aby zademonstrować brakujące obiekty i sposoby obejścia tego problemu podczas pracy z danymi podstawowymi
źródło