Busca genérica usando hibernate + criteria

Estou desenvolvendo um sistema e busquei desenvolver um search que seja bastante genérico e possa ficar num DAO “pai de todos”…

Ainda está dando uns paus e estou tentando resolver…

[code]
@SuppressWarnings(“unchecked”)
protected List<?> searchAsc(String busca, Class classe, String[] campos,
String[] ordens) {
LOGGER.debug("busca = " + busca + " - campo = " + campos
+ " - classe = " + classe.getName() + " - total de ordens = "
+ ordens.length);

	crit = getSession().createCriteria(classe);
	Disjunction disjunction = Restrictions.disjunction();
	List<String> alias = new ArrayList<String>();
	String aClass = "";
	String aClassAlias = "";
	String campo = "";
	String ordem = "";
	// Gera uma lista de alias para campo
	for (int i = 0; i < campos.length; i++) {
		LOGGER.info(campos);
		LOGGER.info(alias);
		aClassAlias = "";
		campo = campos[i];
		// Adiciona uma restrição usando alias
		if (campos[i].split("\\.").length > 1) {
			LOGGER.info("precisa de alias - " + campos[i]);
			aClass = (campos[i].split("\\.")[0]);
			aClassAlias = aClass.substring(0, 3);
			campo = campos[i].split("\\.", 2)[1];
			LOGGER.info("aClass = " + aClass + " - " + "aClassAlias = " + aClassAlias);
			// Verifica se já foi encontrada uma mesma classe
			// Se não foi, adiciona o alias
			if (!alias.contains(aClass)) {
				alias.add(aClass);
				LOGGER.info("alias novo");
				crit.createAlias(aClass, aClassAlias);
				LOGGER.info(alias);
			}
			aClassAlias = aClassAlias + ".";
		}
		//Adiciona a restrição a um disjunction (OR)
		disjunction.add(Restrictions.like(aClassAlias + campo, "%" + busca + "%"));
	}
	//adiciona o disjunction à criteria
	crit.add(disjunction);
	
	// Gera uma lista de alias para ordem
	for (int i = 0; i < ordens.length; i++) {
		LOGGER.info(ordens);
		LOGGER.info(alias);
		aClassAlias = "";
		ordem = ordens[i];
		// Adiciona uma restrição usando alias
		if (ordens[i].split("\\.").length > 1) {
			LOGGER.info("precisa de alias - " + ordens[i]);
			aClass = (ordens[i].split("\\.")[0]);
			aClassAlias = aClass.substring(0, 3);
			ordem = ordens[i].split("\\.", 2)[1];
			LOGGER.info("aClass = " + aClass + " - " + "aClassAlias = " + aClassAlias);
			// Verifica se já foi encontrada uma mesma classe
			// Se não foi, adiciona o alias
			if (!alias.contains(aClass)) {
				alias.add(aClass);
				LOGGER.info("alias novo");
				crit.createAlias(aClass, aClassAlias);
				LOGGER.info(alias);
			}
			aClassAlias = aClassAlias + ".";
		}
		//Adiciona a restrição
		crit.addOrder(Order.asc(aClassAlias + ordem));
	}
return crit.list();
}[/code]

Um exemplo desse método sendo chamado segue abaixo:

searchAsc(nome, Grupo.class, new String[] {"empresa.nome", "nome"}, new String[] {"empresa.nome", "nome"});

O pau que está dando é quando são instanciados mais de dois níveis na chamada… preciso criar um outro alias.

não entendi a real intenção… tipo, qual o re-trabalho que vc estaria tentando evitar ?

A intenção é criar uma busca extremamente genérica que eu possa usar em qualquer DAO, bastando passar os parâmetros.

foi justamente os parametros q não entendi o.O

tipo, então como fazer, pra criar uma busca onde vc precisa que a idade seja maior que 15 anos ? e a cidade da nacionalidade seja São Paulo ?

vc ja pensou no padrão builder ?? eu fiz 1 pra mim, porem ainda não conseguir bolar uma forma de incluir os criterios OR (ou) e NOT (negar outro criterio)…

ai ta assim… a busca

[code] public List<Cidade> findAllByEstado(Estado estado,int firstResult,int maxResult) {
return super.find()
.createAlias(“estado”, “Estado”)
.createAlias(“Estado.pais”, “Pais”)
.insensitiveLike(“estado”, estado)
.asc(“nome”)
.setFirstResult(firstResult)
.setMaxResults(maxResult)
.list();
}

public List&lt;Cidade&gt; findAllContainsNome(String cidade) {
     return super.find()
            .createAlias("estado", "Estado")
            .createAlias("Estado.pais", "Pais")
            .insensitiveLike("nome", cidade, MatchMode.ANYWHERE)
            .asc("nome")
            .asc("Estado.nome")
            .asc("Pais.nome")
            .list();
}[/code]

eu evito akele monte de .add(Restriction.ilike()) addOrder(Order.asc()) etc etc… acho que assim fica + fluente…

o meu builder esta aqui: CriteriaBuilder.java
ele retorna uma interface: Builder<E>.java

a interface é que faz o código ficar fluente

[code] Collection<Cidade> cidades = CriteriaBuilder.search(Cidade.class)
.insensitiveLike(“nome”, “joão”,MatchMode.START)
.createAlias(“estado”, “Estado”)
.createAlias(“Estado.pais”, “Pais”)
.insensitiveLike(“Pais.nome”,“brasil”)
.list();

    for(Cidade c : cidades)
        System.out.println(c.getNome() + "/" + c.getEstado());[/code]

estou pensando em criar automaticamente os Aliases das classes, mais n sei c vale a pena

dessa forma com qualquer navegador ele sai fazendo código fluente… so digitar o “.” que ele mostra as opções…

[quote=Lavieri]vc ja pensou no padrão builder ?? eu fiz 1 pra mim, porem ainda não conseguir bolar uma forma de incluir os criterios OR (ou) e NOT (negar outro criterio)…

ai ta assim… a busca

[code] public List<Cidade> findAllByEstado(Estado estado,int firstResult,int maxResult) {
return super.find()
.createAlias(“estado”, “Estado”)
.createAlias(“Estado.pais”, “Pais”)
.insensitiveLike(“estado”, estado)
.asc(“nome”)
.setFirstResult(firstResult)
.setMaxResults(maxResult)
.list();
}

public List&lt;Cidade&gt; findAllContainsNome(String cidade) {
     return super.find()
            .createAlias("estado", "Estado")
            .createAlias("Estado.pais", "Pais")
            .insensitiveLike("nome", cidade, MatchMode.ANYWHERE)
            .asc("nome")
            .asc("Estado.nome")
            .asc("Pais.nome")
            .list();
}[/code]

eu evito akele monte de .add(Restriction.ilike()) addOrder(Order.asc()) etc etc… acho que assim fica + fluente…

o meu builder esta aqui: CriteriaBuilder.java
ele retorna uma interface: Builder<E>.java

a interface é que faz o código ficar fluente

[code] Collection<Cidade> cidades = CriteriaBuilder.search(Cidade.class)
.insensitiveLike(“nome”, “joão”,MatchMode.START)
.createAlias(“estado”, “Estado”)
.createAlias(“Estado.pais”, “Pais”)
.insensitiveLike(“Pais.nome”,“brasil”)
.list();

    for(Cidade c : cidades)
        System.out.println(c.getNome() + "/" + c.getEstado());[/code]

estou pensando em criar automaticamente os Aliases das classes, mais n sei c vale a pena

dessa forma com qualquer navegador ele sai fazendo código fluente… so digitar o “.” que ele mostra as opções…[/quote]

Eae man, blz? Achei interessante tua idéia de builder. Tem como vc postar o teu método find() do teu Dao??
Agradeço.

A idéia é fazer um DAO Genérico?
Se sim, no site do Hibernate tem um exemplo: https://www.hibernate.org/328.html

Creio que com poucas modificações você pode usar esse DAO genérico no seu projeto. (No meu último projeto tinhamos um DAO Genérico parecido com esse)

Estou tentando fazer da seguinte forma:

  • criei as criterias no FuncionarioDao, para pesquisa por nome, cpf, rg e orgaogestor do funcionario, todos em métodos independentes;
  • criei os métodos para usarem as criterias acima, um para cada (e todos funcionam perfeitamente);
    O problema é que no método que eu criei para testar qual dos campos está preenchido e fornecer o resultado baseando-se nesse campo. o do órgao gestor está errado, como se ele não estivesse funcionando.
    segue o método do orgao gestor e o outro geral:

[code] public List<Funcionario> getFuncionariosOrgaoGestor() {
Session session = HibernateUtil.currentSession();
FuncionarioDao funcionarioDao = new FuncionarioDao(session,
Funcionario.class);
List<Funcionario> lista = funcionarioDao
.pesquisaFuncionariosOrgaoGestor(this.orgaogestor
.getCod_orgaogestor());
return lista;
}

// método que testa todos os campos
public List&lt;Funcionario&gt; getFuncionariosByCampos() {
	List&lt;Funcionario&gt; nome = getFuncionariosNome();
	List&lt;Funcionario&gt; cpf = getFuncionariosCPF();
	List&lt;Funcionario&gt; rg = getFuncionariosRG();
	List&lt;Funcionario&gt; og = getFuncionariosOrgaoGestor();

	if (nome != null) {
		return nome;
	}
	if (cpf != null) {
		return cpf;
	}
	if (rg != null) {
		return rg;
	}
	if (og != null) {
		return og;
	}
	return null;
}[/code]

ou o problema pode ser no objeto na pagina xhtml, que está assim:

&lt;h:outputText value="#{selectOG}" id="msgs-og"/&gt; &lt;h:selectOneMenu value="#{funcionarioHandler.orgaogestor.cod_orgaogestor}" id="og"&gt; &lt;f:selectItem itemValue="4" itemLabel="Selecione" id="selog"/&gt; &lt;f:selectItems value="#{funcionarioHandler.orgaoGestorParaComboBox}" id="sog"/&gt; &lt;/h:selectOneMenu&gt;

Se alguem puder ajudar, agradeço.

resolvido pessoal. O que faltou tratar os atributos como String e não como list, o método getFuncionariosByCampos tratar como List<> e colocar o retorno, e trabalhar corretamente as condiçoes:

[code] public List<Funcionario> getFuncionariosByCampos() {
List<Funcionario> list = new ArrayList<Funcionario>();

	String nome = this.funcionario.getNome();
	String cpf = this.funcionario.getCpf();
	String rg = this.funcionario.getRg();
	Long og = this.orgaogestor.getCod_orgaogestor();

	if (og != null && (nome).isEmpty()) {
		System.out.println("leu primeira condição");
		return getFuncionariosOrgaoGestor();
	} else if ((nome) != null && !(nome).isEmpty()) {
		System.out.println("leu segunda condição");
		return getFuncionariosNome();
	} else if ((rg) != null && !(rg).isEmpty()) {
		System.out.println("leu terceira condição");
		return getFuncionariosRG();
	} else if ((cpf) != null && !(cpf).isEmpty()) {
		System.out.println("leu quarta condição");
		return getFuncionariosCPF();
	}

	return list;
}[/code]

Agradeço a ajuda de todos.