Digamos que tengo dos clases de entidad: SocialApp
ySocialAppType
En SocialApp
Tengo un Atributo: appURL
y uno civil: type
.
En SocialAppType
Tengo tres atributos: baseURL
, name
y favicon
.
El destino de la SocialApp
relación type
es un registro único en SocialAppType
.
Como ejemplo, para varias cuentas de Flickr, habría una cantidad de SocialApp
registros, y cada registro tendría un enlace a la cuenta de una persona. Habría un SocialAppType
registro para el tipo "Flickr", al que SocialApp
apuntarían todos los registros.
Cuando construyo una aplicación con este esquema, recibo una advertencia de que no hay una relación inversa entre SocialAppType
y SocialApp
.
/Users/username/Developer/objc/TestApp/TestApp.xcdatamodel:SocialApp.type: warning: SocialApp.type -- relationship does not have an inverse
¿Necesito un inverso y por qué?
fuente
La documentación de Apple tiene un gran ejemplo que sugiere una situación en la que podría tener problemas al no tener una relación inversa. Vamos a mapearlo en este caso.
Suponga que lo modeló de la siguiente manera:
Tenga en cuenta que tiene una relación uno a uno llamada " tipo ", de
SocialApp
aSocialAppType
. La relación no es opcional y tiene una regla de eliminación "denegar" .Ahora considere lo siguiente:
Lo que esperamos es fallar este contexto, ya que hemos establecido la regla de eliminación como Denegar, mientras que la relación no es opcional.
Pero aquí la salvación tiene éxito.
La razón es que no hemos establecido una relación inversa . Debido a eso, la instancia de socialApp no se marca como modificada cuando se elimina appType. Por lo tanto, no se realiza ninguna validación para socialApp antes de guardar (se supone que no se necesita validación ya que no ocurrió ningún cambio). Pero en realidad ocurrió un cambio. Pero no se refleja.
Si recordamos appType por
appType es nulo.
Extraño, ¿no es así? ¿Obtenemos nil para un atributo no opcional?
Por lo tanto, no tiene problemas si ha establecido la relación inversa. De lo contrario, debe forzar la validación escribiendo el código de la siguiente manera.
fuente
Parafrasearé la respuesta definitiva que encontré en Más desarrollo de iPhone 3 por Dave Mark y Jeff LeMarche.
Apple generalmente recomienda que siempre cree y especifique el inverso, incluso si no usa la relación inversa en su aplicación. Por esta razón, le advierte cuando no proporciona un inverso.
No se requiere que las relaciones tengan un inverso, porque hay algunos escenarios en los que la relación inversa podría perjudicar el rendimiento. Por ejemplo, suponga que la relación inversa contiene un número extremadamente grande de objetos. Eliminar el inverso requiere iterar sobre el conjunto que representa el rendimiento inverso y debilitado.
Pero a menos que tenga una razón específica para no hacerlo, modele el inverso . Ayuda a Core Data a garantizar la integridad de los datos. Si se encuentra con problemas de rendimiento, es relativamente fácil eliminar la relación inversa más adelante.
fuente
La mejor pregunta es, "¿hay alguna razón para no tener un inverso"? Core Data es realmente un marco de gestión de gráficos de objetos, no un marco de persistencia. En otras palabras, su trabajo es administrar las relaciones entre los objetos en el gráfico de objetos. Las relaciones inversas hacen esto mucho más fácil. Por esa razón, Core Data espera relaciones inversas y está escrito para ese caso de uso. Sin ellos, tendrá que administrar la consistencia del gráfico de objetos usted mismo. En particular, es muy probable que Core Data corrompa las relaciones de muchos a muchos sin una relación inversa, a menos que trabaje muy duro para que todo funcione. El costo en términos de tamaño de disco para las relaciones inversas es realmente insignificante en comparación con el beneficio que le brinda.
fuente
Hay al menos un escenario en el que se puede hacer un buen caso para una relación de datos centrales sin una inversa: cuando ya existe otra relación de datos centrales entre los dos objetos, que se encargará de mantener el gráfico del objeto.
Por ejemplo, un libro contiene muchas páginas, mientras que una página está en un libro. Esta es una relación bidireccional de muchos a uno. Eliminar una página solo anula la relación, mientras que eliminar un libro también eliminará la página.
Sin embargo, es posible que también desee realizar un seguimiento de la página actual que se lee para cada libro. Esto podría hacerse con una propiedad "currentPage" en la página , pero luego necesita otra lógica para asegurarse de que solo una página del libro esté marcada como la página actual en cualquier momento. En cambio, establecer una relación de Página actual de Libro a una sola página asegurará que siempre haya solo una página actual marcada y, además, que se pueda acceder fácilmente a esta página con una referencia al libro con simplemente book.currentPage.
¿Cuál sería la relación recíproca en este caso? Algo en gran medida sin sentido. "myBook" o similar podría agregarse en la otra dirección, pero contiene solo la información ya contenida en la relación "libro" para la página, y por lo tanto crea sus propios riesgos. Quizás en el futuro, la forma en que está utilizando una de estas relaciones cambia, lo que resulta en cambios en la configuración de sus datos principales. Si page.myBook se ha usado en algunos lugares donde page.book debería haberse usado en el código, podría haber problemas. Otra forma de evitar esto de manera proactiva también sería no exponer myBook en la subclase NSManagedObject que se utiliza para acceder a la página. Sin embargo, se puede argumentar que es más simple no modelar el inverso en primer lugar.
En el ejemplo descrito, la regla de eliminación para la relación de página actual debe establecerse en "Sin acción" o "Cascada", ya que no existe una relación recíproca con "Anular". (Cascade implica que está arrancando cada página del libro a medida que lo lee, pero eso podría ser cierto si tiene mucho frío y necesita combustible).
Cuando se puede demostrar que la integridad del gráfico de objetos no está en riesgo, como en este ejemplo, y se mejora la complejidad del código y la capacidad de mantenimiento, se puede argumentar que una relación sin una inversa puede ser la decisión correcta.
fuente
currentPage
puede marcar comoOptional
?Si bien los documentos no parecen requerir un inverso, simplemente resolví un escenario que de hecho resultó en "pérdida de datos" al no tener un inverso. Tengo un objeto de informe que tiene una relación de muchos a objetos informables. Sin la relación inversa, cualquier cambio en la relación de muchos se perdió en el relanzamiento. Después de inspeccionar la depuración de Core Data, era evidente que aunque estaba guardando el objeto de informe, nunca se realizaron las actualizaciones al gráfico del objeto (relaciones). Agregué un inverso, aunque no lo uso, y listo, funciona. Por lo tanto, podría no decir que es obligatorio, pero las relaciones sin inversas definitivamente pueden tener efectos secundarios extraños.
fuente
Las inversiones también se usan para
Object Integrity
(por otras razones, vea las otras respuestas):De: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreData/HowManagedObjectsarerelated.html#//apple_ref/doc/uid/TP40001075-CH17-SW1
El enlace proporcionado le da ideas de por qué debería tener un
inverse
conjunto. Sin ella, puede perder datos / integrety. Además, la posibilidad de acceder a un objeto quenil
es más probable.fuente
No hay necesidad de una relación inversa en general. Pero hay algunas peculiaridades / errores en los datos principales en los que necesita una relación inversa. Hay casos en los que faltan relaciones / objetos, aunque no haya ningún error al guardar el contexto, si faltan relaciones inversas. Consulte este ejemplo , que creé para demostrar los objetos que faltan y cómo solucionarlos, mientras trabajaba con datos Core
fuente