Objetos de domínio como ids criam alguns problemas sutis / complexos:
Serialização / desserialização
Se você armazenar objetos como chaves, a serialização do gráfico será extremamente complicada. Você receberá stackoverflowerros ao fazer uma serialização ingênua para JSON ou XML por causa da recursão. Você precisará escrever um serializador personalizado que converta os objetos reais para usar seus IDs, em vez de serializar a instância do objeto e criar a recursão.
Passe objetos para segurança de tipo, mas apenas armazene IDs, e você poderá ter um método de acesso que carrega preguiçosamente a entidade relacionada quando é chamada. O cache de segundo nível cuidará das chamadas subseqüentes.
Vazamentos sutis de referência:
Se você usar objetos de domínio em construtores como você, criará referências circulares que serão muito difíceis de permitir que a memória seja recuperada para objetos que não estão sendo usados ativamente.
Situação ideal:
IDs opacos vs int / long:
Um iddeve ser um identificador completamente opaco que não carrega informações sobre o que identifica. Mas deve oferecer alguma verificação de que é um identificador válido em seu sistema.
Os tipos brutos quebram isso:
int, longE Stringsão os tipos de matérias mais comumente usados para identificadores no sistema RDBMS. Há uma longa história de razões práticas que datam de décadas e todas elas são compromissos que se encaixam na economia spaceou na economia timeou em ambas.
Os IDs seqüenciais são os piores criminosos:
Ao usar um ID seqüencial, você está compactando informações semânticas temporais no ID por padrão. O que não é ruim até que seja usado. Quando as pessoas começam a escrever uma lógica comercial que classifica ou filtra a qualidade semântica do ID, elas estão criando um mundo de dor para futuros mantenedores.
String os campos são problemáticos porque designers ingênuos agrupam informações no conteúdo, geralmente semântica temporal também.
Isso torna impossível criar também um sistema de dados distribuídos, porque não12437379123 é único globalmente. As chances de outro nó em um sistema distribuído criar um registro com o mesmo número são praticamente garantidas quando você obtém dados suficientes em um sistema.
Em seguida, os hacks começam a contorná-lo e tudo se transforma em uma pilha de bagunça fumegante.
Ignorar grandes sistemas distribuídos ( clusters ) torna-se um pesadelo completo quando você começa a tentar compartilhar os dados com outros sistemas também. Especialmente quando o outro sistema não está sob seu controle.
Você acaba com o mesmo problema: como tornar sua identificação globalmente única.
O UUID foi criado e padronizado por um motivo:
UUIDpode sofrer de todos os problemas listados acima, dependendo de qual Versionvocê usar.
Version 1usa um endereço MAC e tempo para criar um ID exclusivo. Isso é ruim porque carrega informações semânticas sobre localização e hora. Isso não é, por si só, um problema, é quando desenvolvedores ingênuos começam a confiar nessas informações para a lógica de negócios. Isso também vaza informações que podem ser exploradas em qualquer tentativa de invasão.
Version 2O uso de usuários UIDou GIDdomian UIDou GUIno lugar a partir Version 1disso é tão ruim quanto Version 1para vazamento de dados e o risco de essas informações serem usadas na lógica de negócios.
Version 3é semelhante, mas substitui o endereço MAC e o tempo por um MD5hash de alguma matriz de byte[]algo que definitivamente tem significado semântico. Não há vazamento de dados para se preocupar, o byte[]não pode ser recuperado a partir do UUID. Isso fornece uma boa maneira de criar deterministicamente o UUIDformulário de instâncias e a chave externa de algum tipo.
Version 4 baseia-se apenas em números aleatórios, o que é uma boa solução, não carrega absolutamente nenhuma informação semântica, mas não é deterministicamente recriada.
Version 5é como Version 4mas usa em sha1vez de md5.
Chaves de domínio e chaves de dados transacionais
Minha preferência por IDs de objetos de domínio é usar Version 5ou, Version 3se houver restrição, Version 5por algum motivo técnico.
Version 3 é ótimo para dados de transações que podem estar espalhados por muitas máquinas.
A menos que você esteja limitado pelo espaço, use um UUID:
Eles têm garantia única, despejando dados de um banco de dados e recarregando em outro. Você nunca precisou se preocupar com IDs duplicados que realmente fazem referência a dados de domínio diferentes.
Version 3,4,5 são completamente opacos e é assim que deveriam ser.
Você pode ter uma única coluna como chave primária com a UUIDe, em seguida, pode ter índices exclusivos compostos para o que teria sido uma chave primária composta natural.
O armazenamento também não precisa ser CHAR(36). Você pode armazenar o campo UUIDem um byte / bit / número nativo para um determinado banco de dados, desde que ele ainda seja indexável.
Legado
Se você tem tipos brutos e não pode alterá-los, ainda pode abstraí-los no seu código.
Usar um Version 3/5de UUIDvocês pode passar o Class.getName()sinal de + String.valueOf(int)como a byte[]e ter uma chave de referência opaca que é recreativa e determinística.