Fala Diego, tudo bem ?
É possível sim fazer mapeamentos para a mesma entidade quando for necessário. Fiz um teste aqui pra poder exemplificar.
Modelo:
@Entity
public class Usuario {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String nome;
@OneToMany
private List<Usuario> contatos;
/**
* @deprecated
*/
public Usuario() {
}
public Usuario(String nome) {
this.nome = nome;
}
//getters and setters
public void adicionaContato(Usuario usuario) {
this.contatos.add(usuario);
}
}
Repository:
@Repository
public class UsuarioDao {
@PersistenceContext
private EntityManager manager;
public void save(Usuario usuario) {
manager.persist(usuario);
}
public Usuario buscaPorId(Integer id) {
return manager.find(Usuario.class, id);
}
public List<Usuario> buscaContatoDoUsuario(int id) {
String jpql = "select contatos from Usuario u join u.contatos contatos where u.id = :id";
return manager.createQuery(jpql, Usuario.class)
.setParameter("id", id)
.getResultList();
}
}
Controller pra teste:
@Controller
public class UsuarioController {
@Autowired
private UsuarioDao usuarioDao;
@GetMapping("/teste/adicao/usuarios")
@ResponseBody
@Transactional
public String adicionaUsuarios() {
List<Usuario> list = Arrays.asList(
new Usuario("Usuário 1"),
new Usuario("Usuário 2"),
new Usuario("Usuário 3"),
new Usuario("Usuário 4"));
list.stream().forEach(usuarioDao::save);
return "Usuarios adicionados";
}
@GetMapping("teste/adicao/contatos")
@ResponseBody
@Transactional
public String adicionaContato() {
Usuario usuario1 = usuarioDao.buscaPorId(1);
Usuario usuario2 = usuarioDao.buscaPorId(2);
Usuario usuario3 = usuarioDao.buscaPorId(3);
Usuario usuario4 = usuarioDao.buscaPorId(4);
//usuario 1 adiciona os demais como contatos
usuario1.adicionaContato(usuario2);
usuario1.adicionaContato(usuario3);
usuario1.adicionaContato(usuario4);
//como objetos estao gerenciados pela JPA no fim desta transação a alteraçao será refletida na base
return "Contatos adicionados ao usuario1";
}
@GetMapping("/teste/query/contatos")
@ResponseBody
public List<Usuario> buscaContatosDeUmUsuario() {
return usuarioDao.buscaContatoDoUsuario(1);
}
}
- Subindo a app temos a seguinte representação no banco:
mysql> desc usuario;
+-------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| nome | varchar(255) | YES | | NULL | |
+-------+--------------+------+-----+---------+----------------+
2 rows in set (0.01 sec)
mysql> desc usuario_contatos
-> ;
+-------------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------+------+-----+---------+-------+
| usuario_id | int(11) | NO | MUL | NULL | |
| contatos_id | int(11) | NO | PRI | NULL | |
+-------------+---------+------+-----+---------+-------+
2 rows in set (0.00 sec)
- Acessando primeiro endpoint
/teste/adicao/usuarios
mysql> select * from usuario;
+----+------------+
| id | nome |
+----+------------+
| 1 | Usuário 1 |
| 2 | Usuário 2 |
| 3 | Usuário 3 |
| 4 | Usuário 4 |
+----+------------+
4 rows in set (0.00 sec)
- Acessando endpoint que testa inserção dos usuarios como contato
/teste/adicao/contatos
mysql> select * from usuario_contatos;
+------------+-------------+
| usuario_id | contatos_id |
+------------+-------------+
| 1 | 2 |
| 1 | 3 |
| 1 | 4 |
+------------+-------------+
3 rows in set (0.00 sec)
- Por fim acessando endpoint que busca contatos de um usuario
/teste/query/contatos
[{
"id": 2,
"nome": "Usuário 2",
"contatos": []
}, {
"id": 3,
"nome": "Usuário 3",
"contatos": []
}, {
"id": 4,
"nome": "Usuário 4",
"contatos": []
}]
Espero ter ajudado. Abraço!