Coleções do tipo Collection, List, Set, Map são umas das estruturas de dados mais utilizadas e o JPA permite seu mapeamento para o modelo relacional de forma simples e eficiente. Você só precisa utilizar as anotações adequadas e não se preocupar como as coleções estão sendo representadas no banco de dados! Vejamos os casos mais comuns de mapeamento de coleções, sejam as coleções classes de entidade, classes embutidas ou tipos básicos:
- Multiplicidade simples entre uma classe de entidade e classes não-entidade (classes embutidadas)
Exemplo: Uma empresa pode ter muitos endereços (Endereço aqui é uma classe embutida):
@Embeddable
class Endereco{}
@Entity
class Empresa{
@ElementCollection
Set<Endereco> enderecos;
//para classes embutidas, utilize @ElementCollection.
}
Opcionalmente você pode especificar como o JPA deve gerar a tabela de coleções no banco de dados fornecendo alguns parâmetros:
@Entity
class Empresa{
@Id int idEmpresa;
@ElementCollection
@CollectionTable(name="logradouro", joinColumns=@JoinColumn(name="emp_id"))
@AttributeOverride(name="address", column=@Column(name="o_nome_q_vc_quiser"))
Collection<Endereco> enderecos;
}
No exemplo anterior, para representar a coleção de endereços da empresa, dissemos para o JPA criar uma tabela chamada logradouro. @JoinColumn representa a chave estrangeira.
Multiplicidade indexada (pares chave/valor)
Pares chave/valor são representados pela interface Map. Coleções desse tipo são muito comuns e são utilizadas em praticamente todas as aplicações. O JPA é bastante flexível com tipos Map. As entidades ou classes embutidas podem representar tanto a chave quanto o valor, ou ainda chave e valor podem ser tipos primitivos.
1 Chave e Valor são tipos primitivos
1 Chave e Valor são tipos primitivos
Exemplo: Um funcionário pode ter vários números de telefone e cada número é de um tipo (comercial, trabalho, casa, etc.):
Essencialmente você só precisa da usar a anotação @ElementCollection para resolver seu problema. Todas as outras são opcionais.
@Entity
public class Funcionario{
@Id private int id;
@ElementCollection
@CollectionTable(name="funcionario_telefone") //opcional, define o nome da tabela no banco
@MapKeyColumn(name="tipo_telefone") ///opcional indica qual coluna armazena achave
@Column(name="numero") //nome da coluna que armazena o valor
private Map<String, String> telefones;
//...
}
2 A chave do Map pode ser uma enum ou uma datapublic enum TipoTelefone {HOME, MOBILE, WORK}
@Entity
public class Funcionario{
@Id private int id;
@ElementCollection
@CollectionTable(name="funcionario_telefone") //opcional, define o nome da tabela no banco
@MapKeyEnumerated(EnumType.STRING)
@MapKeyColumn(name="tipo_telefone") ///opcional indica qual coluna armazena a chave
@Column(name="numero") //nome da coluna que armazena o valor
private Map<TipoTelefone, String> telefones;
//...
}
Caso quisessemos usar como chave o tipo java.util.Date, poderíamos usar a anotação @MapKeyTemporal ao invés de @MapKeyEnumerated.
Exemplo: Um departamento tem vários cubículos cada qual com um funcionário.
A modelagem tradicional um departamento tem muitos funcionários ainda não atenderia eficazmente esse cenário. O software precisa indexar cubículo e funcionário.
4 Chave é o ID da própria entidade que representa o valor do MapA modelagem tradicional um departamento tem muitos funcionários ainda não atenderia eficazmente esse cenário. O software precisa indexar cubículo e funcionário.
@Entity
public class Departamento{
@Id private int id;
@ManyToMany
@JoinTable(name="DEPT_EMP", joinColumns=@JoinColumn(name="DEPT_ID"),
inverseJoinColumn=@JoinColumn(name="EMP_ID"))
@MapKeyColumn(name="CUB_ID")
private Map<String, Funcionario> funcionarioPorCubiculo;
}
É comum e intuitivo indexar a chave do map pelo ID da entidade. No exemplo anterior o poderíamos usar algum atributo do funcionário como identificador do cubículo ao invés do próprio nome atribuído pelo departamento.
@Entity
public class Departamento{
@Id private int id;
@OneToMany(mappedBy="departamento")
@MapKey(name="id")
private Map funcionarios;
}
5 Chave é uma entidade e valor é um tipo básico
Exemplo: Atribuir a senioridade de cada funcionário no departamento em um contexto onde o funcionário pode atuar em vários departamentos e a senioridade podendo variar, uma vez que ela é determinada em função do departamento (um funcionário pode ser pleno no setor de desenvolvimento e junior no departamento de infraestrutura...).
@Entity
public class Department{
@Id private int id;
@ElementCollectionn
@CollectionTable(name="emp_senioridade")
@MapKeyJoinColumn(name="emp_id")
@Column(name="senioridade")
private Map<Employee, Integer> seniorites;
// ...
}
No comments:
Post a Comment