Ajuda com query do JPA

Olá!

Tenho pouca experiência com JPA e estou com dificuldade em montar uma query. Eis o caso.

A classe usuário contém um Set que contém os papéis possíveis a serem desempenhados

@UserRoles @ManyToMany(targetEntity=Papel.class) private Set<Papel> papeis.

E a classe Papel só possui como atributos, o id e nome do papel.

Apesar de ser um Set, cada usuário só possui de fato um papel (Fiz assim pq queria aproveitar a solução que o JBoss Seam oferece para gerenciamento de usuários).

Os papéis possíveis são: Administrador, Gerente, Revisor, Pesquisador, Educador, Usuário comum.
Os papéis acumulam responsabilidades. Assim, seu eu sou um usuário com papel Pesquisador, acabo sendo também um usuário do tipo Educador e Usuário comum.
O que eu gostaria de fazer é montar um query que retornasse todos os usuários que possuem um determinado papel aproveitando a regra de negócio descrita acima.

Então, para selecionar todos os usuários que podem atuar como revisores, teria uma query do tipo:

Como posso montar esta query?

Obrigado!


List<Papel> papeis = new ArrayList<Papel>();

papeis.add(blablablablbal....




select u from Usuario u where u.papeis in (:papeis);


query.setParameter("papeis), papeis);


flw

Opa!
Valeu pela ajuda!!

Mas ainda está dando problemas.

O código ficou assim:

[code]List papeis = entityManager.createQuery(“select p from Papel p where p.nome = ‘Administrador’ or p.nome = ‘Gerente’ or p.nome = ‘Pesquisador’”).getResultList();

	String sql = "select u from Usuario u where u.papeis in ( :papeis ) order by u.nome";
	
	Query query = entityManager.createQuery(sql);
	query.setParameter("papeis", papeis);
	
	listaUsuariosPesquisadores = query.getResultList();[/code]

E está sendo lançado a seguinte exceção

Caused by: org.hibernate.exception.SQLGrammarException: could not execute query at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:90) at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66) at org.hibernate.loader.Loader.doList(Loader.java:2231) at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2125) at org.hibernate.loader.Loader.list(Loader.java:2120) at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:401) at org.hibernate.hql.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:361) at org.hibernate.engine.query.HQLQueryPlan.performList(HQLQueryPlan.java:196) at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1148) at org.hibernate.impl.QueryImpl.list(QueryImpl.java:102) at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:67) ... 178 more Caused by: java.sql.SQLException: No value specified for parameter 1 at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:910) at com.mysql.jdbc.PreparedStatement.fillSendPacket(PreparedStatement.java:1718) at com.mysql.jdbc.PreparedStatement.fillSendPacket(PreparedStatement.java:1666) at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:1377) at org.jboss.resource.adapter.jdbc.WrappedPreparedStatement.executeQuery(WrappedPreparedStatement.java:342) at org.hibernate.jdbc.AbstractBatcher.getResultSet(AbstractBatcher.java:208) at org.hibernate.loader.Loader.getResultSet(Loader.java:1808) at org.hibernate.loader.Loader.doQuery(Loader.java:697) at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:259) at org.hibernate.loader.Loader.doList(Loader.java:2228)

O conteúdo do List está preenchido corretamente mas o erro persiste.

abraço!

Eu pensei que Papeis era uma Enum

List papeis, nao vai funcionar como parametro pq dentro do IN(:papeis); o parametro tem que ser algo que possa ser convertido numa String ou numero

O seu relacionamento é esse:

User N - N Papel

?

Aqui vai a classe Usuário e Papel na integra

[code]package br.ufrj.cos.portalfees.entity;

import java.io.Serializable;
import java.util.List;
import java.util.Set;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.Transient;
import javax.persistence.Version;

import org.hibernate.validator.Email;
import org.hibernate.validator.Length;
import org.hibernate.validator.NotNull;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.security.management.UserEnabled;
import org.jboss.seam.annotations.security.management.UserPassword;
import org.jboss.seam.annotations.security.management.UserPrincipal;
import org.jboss.seam.annotations.security.management.UserRoles;

@Entity
@Name(“usuario”)
public class Usuario implements Serializable
{
/**
*
*/
private static final long serialVersionUID = -1929518031977185775L;
private Long id;
private Integer version;
private String nome;
private String email;
private String login;
private String senha;
private String titulo;
private Boolean profissional;
private boolean acessoAutorizado;
private Set papeis;
private List areaPesquisaList;
private InstituicaoEnsino instituicaoEnsino;
private Boolean recebeMensagensEmail;

public Boolean getRecebeMensagensEmail() {
	return recebeMensagensEmail;
}

public void setRecebeMensagensEmail(Boolean recebeMensagensEmail) {
	this.recebeMensagensEmail = recebeMensagensEmail;
}

@ManyToOne
public InstituicaoEnsino getInstituicaoEnsino() {
	return instituicaoEnsino;
}

public Boolean isProfissional() {
	return profissional;
}

public void setProfissional(Boolean profissional) {
	this.profissional = profissional;
}

public void setInstituicaoEnsino(InstituicaoEnsino instituicaoEnsino) {
	this.instituicaoEnsino = instituicaoEnsino;
}

@NotNull
public String getTitulo() {
	return titulo;
}

public void setTitulo(String titulo) {
	this.titulo = titulo;
}

@NotNull
@UserPrincipal
public String getLogin() {
	return login;
}

public void setLogin(String login) {
	this.login = login;
}

@NotNull
@Length(min=6, message="#{messages['usuario.senha.tamanhoMinimo.exception']}")
@UserPassword(hash="md5")
public String getSenha() {
	return senha;
}

public void setSenha(String senha) {
	this.senha = senha;
}

@NotNull
public String getNome() {
	return nome;
}

public void setNome(String nome) {
	this.nome = nome;
}

@NotNull
@Email
public String getEmail() {
	return email;
}

public void setEmail(String email) {
	this.email = email;
}

@Id @GeneratedValue
public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

@Version
public Integer getVersion() {
    return version;
}

private void setVersion(Integer version) {
    this.version = version;
}

@UserRoles
@ManyToMany(targetEntity=Papel.class)
public Set<Papel> getPapeis() {
	return papeis;
}

public void setPapeis(Set<Papel> papeis) {
	this.papeis = papeis;
}

@ManyToMany(mappedBy="usuarioList")
public List<AreaPesquisa> getAreaPesquisaList() {
	return areaPesquisaList;
}

public void setAreaPesquisaList(List<AreaPesquisa> areaPesquisaList) {
	this.areaPesquisaList = areaPesquisaList;
}

@UserEnabled
public boolean isAcessoAutorizado() {
	return acessoAutorizado;
}

public void setAcessoAutorizado(boolean acessoAutorizado) {
	this.acessoAutorizado = acessoAutorizado;
}

@Transient
public String getPerfil() {
	String perfil = null;
	for (Papel p :getPapeis()) {
		perfil = p.getNome();
	}
	return perfil;
}

@Override
public boolean equals(Object o) {
	Usuario usuario = (Usuario) o;
	if (usuario.getNome().equals(this.nome)) {
		return true;
	}
	return false;
}

}
[/code]

[code]package br.ufrj.cos.portalfees.entity;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.security.management.RoleName;

@Entity
@Name(“papel”)
public class Papel implements Serializable {
/**
*
*/
private static final long serialVersionUID = 8076316478170311419L;
private Long id;
private String nome;

@Id @GeneratedValue
public Long getId() {
	return id;
}
public void setId(Long id) {
	this.id = id;
}

@RoleName
public String getNome() {
	return nome;
}
public void setNome(String nome) {
	this.nome = nome;
}

}
[/code]

Apesar de ser uma entidade, a classe Papel só vai ter como valores aqueles que citei la no primeiro post (Administrador, Gerente, etc). Fiz deste jeito pensando em uma “upgrade”, onde poderiam existir vários papeis.

Tem como eu fazer algo do tipo String sql = "select u from Usuario u where u.papeis.nome in ( :papeis ) order by u.nome";
e então passar um List com as strings correspondentes?

abraço!

cara eu nao testei isso mas tenta assim

select u from User u JOIN u.papeis as p where p.nome in (:nomes)

eu vi isso aki

http://docs.jboss.org/hibernate/stable/entitymanager/reference/en/html/queryhql.html

flw

cara fiz uns testes rapidos e funcionou

confere os anexos

flw

Na verdade, o mapeamento entre Usuario e Papel não deveria ser N-N. Havia feito deste jeito por causa da forma sugerida pelo guia de referência do Seam. É que pra mim, a annotation @Roles só funcionava com mapeamentos N-N.

Mudei o relacionamento pra 1-N e usei a query que você sugeriu. Funcionou!!!

Valeu pela ajuda!!!

Abraço!

mas cara se ficar user 1 - N papel, vc tah dizendo que um papel soh pode ter 1 usuario e 1 usuario pode ter varios papeis

pelo que eu entendi 1 papel deveria ter varios users e 1 user deveria ter varios papeis

flw

Sim, concordo contigo. Voltei pro jeito que você recomendou.

Sem querer abusar, uma última ajuda: Eu não lembrei que a query deve listar os usuários que possuam um determinado papel e que não estejam em uma determinada area de pesquisa.
Tentei fazer a query do jeito abaixo mas o resultado está errado. O relacionamento entre usuário e area de pesquisa também é N-N

        @Override
	public List<Usuario> getListaUsuariosPesquisadores() {
		List<String> papeis = new ArrayList<String>();
		papeis.add("Administrador");
		papeis.add("Gerente");
		papeis.add("Pesquisador");
		
		List<String> areasPesquisa = new ArrayList<String>();
		areasPesquisa.add(areaPesquisa.getNome());
		
		String sql = "select u from Usuario u JOIN u.papeis p JOIN u.areaPesquisaList ap where p.nome in ( :papeis ) and ap.nome not in (:nomeAreaPesquisa) order by u.nome";
		Query query = entityManager.createQuery(sql);
		query.setParameter("papeis", papeis);
		query.setParameter("nomeAreaPesquisa", areasPesquisa);
		
		listaUsuariosPesquisadores = query.getResultList();
		return listaUsuariosPesquisadores;
	}

Tô colocando uma figura em anexo pra ficar mais fácil de visualizar o problema. A idéia é listar do lado esquerdo somente os usuários que possuam um determinado papel (neste caso corresponde a pesquisador)
e que não estejam cadastrados na área de pesquisa em edição (não pode repetir os usuários que estão no lado direito).

Mais uma vez, valeu pela ajuda!!!
Abraço!




@Stateless
public class EJBTester implements EJBTesterRemote {
	@PersistenceContext
	EntityManager em;

	@SuppressWarnings("unchecked")
	public void go() {

		Papel admin = new Papel();
		admin.setNome("admin");
		em.persist(admin);

		Papel jao = new Papel();
		jao.setNome("jao");
		em.persist(jao);

		User stag = new User();
		stag.setUsername("stag");
		em.persist(stag);
		stag.getPapeis().add(jao);
		jao.getUsers().add(stag);

		User stag2 = new User();
		stag2.setUsername("stag2#");
		em.persist(stag2);
		stag2.getPapeis().add(jao);
		jao.getUsers().add(stag2);

		User chefe = new User();
		chefe.setUsername("chief");
		em.persist(chefe);
		chefe.getPapeis().add(admin);
		admin.getUsers().add(chefe);

		User diretoo = new User();
		diretoo.setUsername("dire");
		em.persist(diretoo);
		diretoo.getPapeis().add(admin);
		admin.getUsers().add(diretoo);

		AreaPesquisa nanotech = new AreaPesquisa("nano");
		AreaPesquisa robotics = new AreaPesquisa("robot");
		em.persist(nanotech);
		em.persist(robotics);

		nanotech.getUsers().add(chefe);
		chefe.getAreasPesquisa().add(nanotech);

		robotics.getUsers().add(diretoo);
		diretoo.getAreasPesquisa().add(robotics);

		robotics.getUsers().add(stag2);
		robotics.getUsers().add(stag);
		stag.getAreasPesquisa().add(robotics);
		stag2.getAreasPesquisa().add(robotics);

		em.flush();

		List<String> papeis = new ArrayList<String>();
		papeis.add("admin");

		List<String> areas = new ArrayList<String>();
		areas.add("robot");

		List<User> resultList = em
				.createQuery(
						"SELECT ua FROM AreaPesquisa area JOIN area.users ua JOIN ua.papeis up"
								+ " WHERE up.nome in(:papeis) AND area.nome not in(:areas)")
				.setParameter("papeis", papeis).setParameter("areas", areas)
				.getResultList();

		System.out.println(resultList);

	}

}

deve retornar o user chefe

flw