Solucionado (ver solução)
Solucionado
(ver solução)
15
respostas

Relacionamento muitos para muitos mesma entidade

Olá,

Tenho uma entidade que tem cardinalidade de muitos para muitos com ela mesmo: um usuário possui vários contatos, um contato é convidado por vários usuários, um contato é um usuário. Como resolver essa situação?

15 respostas

Não tem nenhum instrutor para me responder?

Olá Diego, tudo bem? espero que sim!

Não sou especialista, mais posso tentar ajudar.

No JPA, você tem a anotação @ManyToMany, onde você pode configurar no seu mapeamento! Colocando essa anotação, o hibernate irá criar uma tabela no "meio" relacionando as duas entidades.

qualquer dificuldade, posta o código aqui, que agente te ajuda!

espero ter ajudado.

Diego você quer fazer um relacionamento muitos para muitos?

E Diego o prazo dos instrutores responderem é de um dia kkk, eles iam acabar te respondendo logo logo, você tá usando hibernete com JPA? Se sim, você pode fazer algo assim.

public class Usuario {
    private Long codigo;
    @ManyToMany
    private List<Contato> contatos = new ArrayList<>();
}
public class Contato {
    private Long codigo;
    @ManyToMany
    private List<Usuario> usuarios = new ArrayList<>();
}

Aqui irá gerar uma tabela associativa, pegando os 2 codigo das classes e juntando, a tabela associativa é para isso mesmo, para verificar e entender melhor da uma olhada no seu banco de dados que ela irá estar lá.

Obrigado gente,

Essa dúvida irá auxiliar muitos alunos, verifiquei que existe muito essa dúvida na internet.

O cenário é o seguinte: possuo a entidade usuário, que é um contato, não sei se a melhor prática, é criar uma classe para cada um, como feito acima: class Usuario, class Contato, ou se é melhor criar esses dois mapeamentos na própria class Usuario, apontando para o usuario, por exemplo:

@Id
@Column(name="id_usuario")
@GeneratedValue
private Long usuarioId;

@ManyToMany(cascade={CascadeType.ALL})
    @JoinTable(name="rl_amizade",
        joinColumns={@JoinColumn(name="id_usuario")},
        inverseJoinColumns={@JoinColumn(name="id_contato")})
private Set<Usuario> contatos = new HashSet<Usuario>();

@ManyToMany(mappedBy="contatos")
private Set<Usuario> contatosde = new HashSet<Usuario>();

Como seria essa cadinalidade: muitos para muitos é um na orientação à objetos, sabemos como resolver no relacionamento entre tabelas, porém precisamos entender como funciona no OO, contato poderia ser uma subclasse de usuario? Poderiam contextualizar para nós, alunos, esse cenário na OO.

Desde já agradeço!

Estou tendo problemas no momento de realizar a consulta. Como o relacionamento é @ManyToMany, a sessão(EntityManager) é fechada antes do response, o fetchType é LAZY. Quando o usuário loga, quero realizar uma consulta assim: "buscar usuário e todos os filhos quando a senha e email forem os seguintes". pensei em fazer algo assim, mas está dando erro:

jpql = "select u from Usuario u join fetch u.contatos where u.email = pEmail and u.senha = pSenha";

quero que ele carregue um usuário e todos os filhos, mas não entendo como funciona a regra e sintaxe do jpql aqui, não sei qual a ordem. Poderiam me auxiliar?

Diego você quer fazer um login quando entrar no sistema, e quando fazer o select verificar se a senha e email bate com oque tem cadastro no banco?

Pode fazer algo assim.

Se tiver usando CDI no projeto e se tiver tudo ok
 para o CDI cuidar das transação pode fazer assim
@Inject
private EntityManager manager;

public Usuario verificar(Usuario usuario) {
    Query query = manager.createQuery("Select u FROM Usuario u JOIN FETCH u.contatos WHERE u.email = :pEmail and u.senha = :pSenha");
query.setParameter("pEmail" usuario.getEmail());
query.setParameter("pSenha" usuario.getSenha());
Usuario usuarioBuscado = (Usuario) query.getSingleResult();
return usuarioBuscado;
}

Estou sem minha IDE aqui ai fica dificil de saber de cor os códigos kkk porque sempre uso o autoCOMPLETE, se tiver algum erro de digitação no codigo você conserta, mais o rumo é esse

Diego sim, você fez certo dividir suas classes com seus respectivos atributos e metodos, deixando as classes com regra de negocios delas mesmo, é uma boa pratica criar classes para seprar uma responsabilidade de uma outra classe, imagina se você tivesse um classe, igual voce citou e com usuario e contatos? Imagina os atributos dessa classe? Seria uma bagunça destinguir os atributos, fora os metodos kkkk, Deixando do jeito que você fez, ganha tempo em manutenção de código.

Quando uso JOIN FETCH, ele realiza o WHERE email/senha para cada usuário, então retorna NULL.

Quando uso LEFT JOIN, ele realiza o WHERE corretamente mas não carrega as listas, porque ele exclui. Mas trás o usuário correspondente.

Gostaria de saber como realmente fica o select neste caso: buscar usuário de acordo com o email e senha passados, e carregar os filhos da relação.

Olá Alisson, poderia me ajudar?

Opa Diego, vamos lá eu li um livro da casa do código que sempre me mostrou fazer junção entre tabelas, com o JOIN FETCH.

Quando uso JOIN FETCH, ele realiza o WHERE email/senha para cada usuário, então retorna NULL.

JOIN FETCH faz a junção da sua tabela, e a questão X não é essa? Trazer apenas um usuario logado? Quando você passa o join fetch ele te retorna null? Tem certeza? porque no caso seu, ele está fazendo a junção com a tabela contatos e verificando se tem um email e senha que você passou. Você está tendo problemas?

Oque eu entendi que você quer fazer é um select que busca seu usuario e contato, seria isso?

Porque se for, você pode muito bem usar o JOIN FETCH para isso, basta fazer um select para ir no banco e verificar se tem algum usuario com a senha.

public Usuario verificar(Usuario usuario) {
        Query query = manager
                .createQuery("Select u from Usuario u JOIN FETCH u.nivelDeAcesso WHERE u.login = :pLogin and u.senha = :pSenha");
        query.setParameter("pLogin", usuario.getLogin());
        query.setParameter("pSenha", usuario.getSenha());
        try {
            Usuario resultado = (Usuario) query.getSingleResult();
            return resultado;
        } catch (NoResultException e) {
            return null;
        }
    }

Aqui tem um exemplo disso, irá fazer um select e me retorna um usuario se a senha e o login bater com algum no banco de dados, e se não bater irá me retornar null, mais já tó tratando ali para não receber a exception.

Posta seu código aqui?

solução!

Olá Alisson, fiz da mesma forma:

String jpql = "select u from Usuario u join fetch u.contatos where u.email = :pEmail and u.senha = :pSenha";
query = manager.createQuery(jpql, Usuario.class);
query.setParameter("pEmail", usuario.getEmail());
query.setParameter("pSenha", usuario.getSenha());
    try {
        setUsuario(query.getSingleResult());
        return getUsuario();
    } catch (NoResultException e) {
            return null;
    }

O problema que ele não carrega a lista dessa forma.

Exatamente! Obrigado! xD

Precisando estamos ai kkk