Digamos que eu tenho duas classes de entidade: SocialApp
eSocialAppType
Em SocialApp
Tenho um atributo: appURL
e um relacionamento: type
.
Em SocialAppType
Tenho três atributos: baseURL
, name
e favicon
.
O destino do SocialApp
relacionamento type
é um registro único em SocialAppType
.
Como exemplo, para várias contas do Flickr, haveria vários SocialApp
registros, com cada registro mantendo um link para a conta de uma pessoa. Haveria um SocialAppType
registro para o tipo "Flickr", para o qual todos os SocialApp
registros apontariam.
Quando crio um aplicativo com esse esquema, recebo um aviso de que não há relação inversa entre SocialAppType
e SocialApp
.
/Users/username/Developer/objc/TestApp/TestApp.xcdatamodel:SocialApp.type: warning: SocialApp.type -- relationship does not have an inverse
Preciso de um inverso e por quê?
fonte
A documentação da Apple tem um ótimo exemplo que sugere uma situação em que você pode ter problemas por não ter um relacionamento inverso. Vamos mapeá-lo neste caso.
Suponha que você modelou da seguinte maneira:
Observe que você tem um relacionamento pessoal chamado " tipo ", de
SocialApp
paraSocialAppType
. O relacionamento não é opcional e possui uma regra de exclusão "negar" .Agora considere o seguinte:
O que esperamos é deixar de salvar o contexto, pois definimos a regra de exclusão como Negar, enquanto o relacionamento não é opcional.
Mas aqui a defesa é bem-sucedida.
A razão é que não estabelecemos um relacionamento inverso . Por esse motivo, a instância socialApp não é marcada como alterada quando appType é excluído. Portanto, nenhuma validação acontece para o socialApp antes de salvar (ela não assume nenhuma validação necessária, pois nenhuma alteração ocorreu). Mas, na verdade, uma mudança aconteceu. Mas isso não se reflete.
Se lembrarmos de appType por
appType é nulo.
Estranho, não é? Ficamos nulos por um atributo não opcional?
Portanto, você não terá problemas se tiver estabelecido um relacionamento inverso. Caso contrário, você precisará forçar a validação escrevendo o código da seguinte maneira.
fonte
Parafraseando a resposta definitiva que encontrei no More iPhone 3 Development, de Dave Mark e Jeff LeMarche.
A Apple geralmente recomenda que você sempre crie e especifique o inverso, mesmo se você não usar o relacionamento inverso no seu aplicativo. Por esse motivo, ele avisa quando você falha em fornecer um inverso.
Não é necessário que os relacionamentos tenham um inverso, porque existem alguns cenários nos quais o relacionamento inverso pode prejudicar o desempenho. Por exemplo, suponha que o relacionamento inverso contenha um número extremamente grande de objetos. A remoção do inverso requer iteração sobre o conjunto que representa o desempenho inverso e enfraquecedor.
Mas, a menos que você tenha um motivo específico para não, modele o inverso . Ajuda o Core Data a garantir a integridade dos dados. Se você tiver problemas de desempenho, é relativamente fácil remover o relacionamento inverso posteriormente.
fonte
A melhor pergunta é: "existe uma razão para não ter um inverso"? O Core Data é realmente uma estrutura de gerenciamento de gráfico de objetos, não uma estrutura de persistência. Em outras palavras, seu trabalho é gerenciar os relacionamentos entre objetos no gráfico de objetos. Relações inversas tornam isso muito mais fácil. Por esse motivo, o Core Data espera relacionamentos inversos e é gravado para esse caso de uso. Sem eles, você precisará gerenciar a consistência do gráfico de objetos. Em particular, é provável que relacionamentos com muitos sem um relacionamento inverso sejam corrompidos pelo Core Data, a menos que você se esforce muito para manter as coisas funcionando. O custo em termos de tamanho do disco para os relacionamentos inversos é realmente insignificante em comparação com o benefício que você obtém.
fonte
Há pelo menos um cenário em que um bom argumento pode ser feito para um relacionamento de dados principais sem um inverso: quando já existe outro relacionamento de dados principais entre os dois objetos, que cuidará da manutenção do gráfico de objetos.
Por exemplo, um livro contém muitas páginas, enquanto uma página está em um livro. Esse é um relacionamento bidirecional de muitos para um. A exclusão de uma página apenas anula o relacionamento, enquanto a exclusão de um livro também exclui a página.
No entanto, você também pode acompanhar a página atual que está sendo lida para cada livro. Isso pode ser feito com uma propriedade "currentPage" na página , mas você precisa de outra lógica para garantir que apenas uma página do livro seja marcada como a página atual a qualquer momento. Em vez disso, estabelecer um relacionamento currentPage de Book para uma única página garantirá que sempre haverá apenas uma página atual marcada e, além disso, que essa página possa ser acessada facilmente com uma referência ao livro com simplesmente book.currentPage.
Qual seria a relação recíproca neste caso? Algo em grande parte sem sentido. "myBook" ou similar pode ser adicionado novamente na outra direção, mas contém apenas as informações já contidas no relacionamento "book" da página e, portanto, cria seus próprios riscos. Talvez no futuro, a maneira como você está usando um desses relacionamentos seja alterada, resultando em alterações na configuração dos dados principais. Se o page.myBook tiver sido usado em alguns lugares onde o page.book deveria ter sido usado no código, pode haver problemas. Outra maneira de evitar isso proativamente também seria não expor o myBook na subclasse NSManagedObject que é usada para acessar a página. No entanto, pode-se argumentar que é mais simples não modelar o inverso em primeiro lugar.
No exemplo descrito, a regra de exclusão para o relacionamento currentPage deve ser definida como "No Action" ou "Cascade", pois não há relacionamento recíproco para "Nullify". (Cascade implica que você está rasgando todas as páginas do livro enquanto o lê, mas isso pode ser verdade se você estiver particularmente frio e precisar de combustível.)
Quando for demonstrado que a integridade do gráfico de objeto não corre risco, como neste exemplo, e a complexidade e a manutenção do código são aprimoradas, pode-se argumentar que um relacionamento sem inverso pode ser a decisão correta.
fonte
currentPage
ser marcado comoOptional
?Embora os documentos não pareçam exigir um inverso, apenas resolvi um cenário que de fato resultou em "perda de dados" por não ter um inverso. Eu tenho um objeto de relatório que tem um relacionamento com muitos em objetos reportáveis. Sem o relacionamento inverso, quaisquer alterações no relacionamento para muitos eram perdidas no relançamento. Após inspecionar a depuração do Core Data, ficou claro que, embora eu estivesse salvando o objeto de relatório, as atualizações no gráfico do objeto (relacionamentos) nunca estavam sendo feitas. Eu adicionei um inverso, mesmo que não o use, e pronto, ele funciona. Portanto, pode não dizer que é necessário, mas relacionamentos sem inversos podem definitivamente ter efeitos colaterais estranhos.
fonte
Inversos também são usados para
Object Integrity
(por outros motivos, consulte as outras respostas):De: https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreData/HowManagedObjectsarerelated.html#//apple_ref/doc/uid/TP40001075-CH17-SW1
O link fornecido fornece idéias de por que você deveria ter um
inverse
conjunto. Sem ele, você pode perder dados / integridade. Além disso, a chance de você acessar um objeto quenil
é mais provável.fonte
Não há necessidade de relacionamento inverso em geral. Mas existem algumas peculiaridades / erros nos dados principais em que você precisa de um relacionamento inverso. Há casos em que os relacionamentos / objetos desaparecem, mesmo que não haja erro ao salvar o contexto, se houver um relacionamento inverso ausente. Verifique este exemplo , que eu criei para demonstrar a falta de objetos e como solução alternativa, enquanto trabalhava com dados principais
fonte