[Resolvido] Hibernate Composite ID Projections

19 respostas
M

Pessoal estou com o seguinte problema, tenho uma “Composite Key” chave composta e preciso limitar os campos de retorno
ja fiz isso usando:

criteria.setProjection(Projections.projectionList().add(Projections.property("field"))....)

Até ai funcionou legal na outra consulta que precisei fazer, mas agora tenho um @EmbeddedId
e não consigo fazer…

Alguem sabe oque preciso fazer ?

OBS: Preciso limitar a quantidade de fields pois essa tabela tem 90 fields … modelagem horrivel, eu sei, banco legado :?

[Editado]
Aqui esta minha criteria:

Criteria c = getSession().createCriteria(Cliente.class);
        c.add(Restrictions.eq("cdFilial", cdFilial));
        c.add(Restrictions.eq("cdVendedor", cdVendedor));
       

        c.setProjection(Projections.projectionList()
                .add(Projections.property("clientePK.cdCliente"))
                .add(Projections.property("clientePK.cdFilial"))
        );
        c.setResultTransformer(Transformers.aliasToBean(Cliente.class));

Exception:

Hibernate: select this_.CD_CLIENTE as y0_, this_.CD_FILIAL as y1_ from CLIENTE this_ where y1_=? and this_.CD_VENDEDOR=?
org.hibernate.exception.GenericJDBCException: could not execute query
Column unknown
Y1_
At line 1, column 81.

Vejam que CD_FILIAL no where esta como y1_ :roll:

19 Respostas

O

Será que um createAlias ajuda? O Hibernate Criteria tem essas loucas quando usa-se criteria em coleções e composite-keys.

M

hmmm resolvi o esquema do alias ali… mas ele faz o select e não mapeia a chave composta em clientePK como deveria… ele deixa a chave em branco :evil:

O

Hmm, deixe-me tirar uma dúvida... você quer na verdade retornar apenas a PK, certo?

Então não deveria ser algo assim?

Criteria c = getSession().createCriteria(Cliente.class);   
        c.add(Restrictions.eq("cdFilial", cdFilial));   
        c.add(Restrictions.eq("cdVendedor", cdVendedor));   
         
  
        c.setProjection(Projections.projectionList()   
                .add(Projections.property("clientePK")) 
        );   
        c.setResultTransformer(Transformers.aliasToBean(Cliente.class));

Outra coisa que você pode fazer é ir eliminando o problema aos poucos. Primeiro faria a consulta normal, depois apenas colocaria as projections e depois o result transformer. Entendeu? Por partes, aí dá para isolar o erro.

M

Sim entendi… mas ja fiz isso, sempre faço por partes…
Deveria ser como você falou BUT:

org.hibernate.QueryException: property does not map to a single column: c.clientePK
O
Criteria c = getSession().createCriteria(Cliente.class);     
        c.add(Restrictions.eq("cdFilial", cdFilial));     
        c.add(Restrictions.eq("cdVendedor", cdVendedor));     
     
        c.setProjection(Projections.property("clientePK")); 

System.out.println(c.list());

Me parece que a projection deveria ser assim, não? Vamos remover o transformer por enquanto.

Outra coisa, esses campos cdFinal e cdVendedor estão na PK ou na entidade cliente? Mande sua entidade e a PK.

M
Cliente {
 clientePK, nmCilente...
}

ClientePK {
 cdCliente, cdFilial
}

Mas como eu disse, a linha:

c.setProjection(Projections.property("clientePK"));

Retorna uma Exception:

Ocorre antes mesmo de executar a query…

Deveria ser como você falou OU assim:

c.setProjection(Projections.id());

Mas assim ele retorna os campos erroneamente no sql:

sem “,” separando os campos, causando erro no sql

V
Fiz um teste aqui e consegui fazer da seguinte forma:
Criteria c = session.createCriteria(Cliente.class);
		
ProjectionList list = Projections.projectionList();
list.add(Projections.property("id.rg"));
list.add(Projections.property("id.cpf"));
c.setProjection(list);
		
c.setResultTransformer(Transformers.aliasToBean(Cliente.class));
O "id" é uma classe ClienteId com rg e cpf.

Vê se te ajuda! Flw! :thumbup:

M
von.juliano:
Fiz um teste aqui e consegui fazer da seguinte forma:
Criteria c = session.createCriteria(Cliente.class);
		
ProjectionList list = Projections.projectionList();
list.add(Projections.property("id.rg"));
list.add(Projections.property("id.cpf"));
c.setProjection(list);
		
c.setResultTransformer(Transformers.aliasToBean(Cliente.class));
O "id" é uma classe ClienteId com rg e cpf.

Vê se te ajuda! Flw! :thumbup:

Quais metodos tem na tua classe Cliente ?
setRG ? setCPF ? ou apenas setID ?

[Editado]
Como você mostrou vai certo o SQL mas não adiciona um PK, ele retorna null...

mas o sql fica certo...


select this_.CD_CLIENTE as y0_, this_.CD_FILIAL as y1_ from CLIENTE this_ where (this_.CD_FILIAL=? and this_.CD_VENDEDOR=?)

V

Na Cliente tem apenas setId e getId, os sets e gets do rg e do cpf estão na ClienteId.

M

Hmmm editei o tópico anterior… estou frustrado ja …

O

Quando usamos composite key dá pra fazer isso:

Criteria c = getSession().createCriteria(Cliente.class);

ClientePK pk = new ClientePK();
pk.setCdFilial(cdFilial);
pk.setCdVendedor(cdVendedor);

c.add(Restrictions.eq("clientePK", pk));
       
c.setProjection(Projections.property("clientePK"));
  
System.out.println(c.list());

Eu só não entendi uma coisa... você está querendo fazer um select filtrando pela PK, mas vai retornar uma lista de PK? Não me faz muito sentido isso.

M
otavio:
Quando usamos composite key dá pra fazer isso:
Criteria c = getSession().createCriteria(Cliente.class);

ClientePK pk = new ClientePK();
pk.setCdFilial(cdFilial);
pk.setCdVendedor(cdVendedor);

c.add(Restrictions.eq("clientePK", pk));
       
c.setProjection(Projections.property("clientePK"));
  
System.out.println(c.list());

Eu só não entendi uma coisa... você está querendo fazer um select filtrando pela PK, mas vai retornar uma lista de PK? Não me faz muito sentido isso.

Vou testar... mas oque quero não são apenas as PK's, quero limitar a quantidade de fields de retorno no sql pois isso consome muito processo...
Veja assim:
Tenho 3mil clientes, cada cliente tem 88 fields com seus dados dentro, limitando para 8 como eu quero é muito mais rapido!

O

maniacs:
Vou testar… mas oque quero não são apenas as PK’s, quero limitar a quantidade de fields de retorno no sql pois isso consome muito processo…
Veja assim:
Tenho 3mil clientes, cada cliente tem 88 fields com seus dados dentro, limitando para 8 como eu quero é muito mais rapido!

Mas se você está fazendo a pesquisa pela PK, entendo que vai retornar apenas 1 registro. Se retornar mais de um, então não dá para ser PK, pois pk é unica.

V
Me desculpe, não havia notado um detalhe, os valores vem nulos por causa do ResultTransformer. Crie o seu próprio que os valores serão setados corretamente:
public class ClienteTransformer implements ResultTransformer {

	public List transformList(List list) {
		return list;
	}

	public Object transformTuple(Object[] values, String[] aliases) {
		Cliente c = new Cliente();
		ClienteId id = new ClienteId();
		id.setRg((String)values[0]);
		id.setCpf((String)values[1]);
		
		c.setId(id);
		return c;
	}
}
Vê se agora resolve! :D
M

Não estou filtrando por toda PK, apenas pelo cdFilial
e fazer:

ProjectionList list = Projections.projectionList();
list.add(Projections.property("clientePK"));
c.setProjection(list);

retorna como eu disse:

Estranho … se eu fazer para cada campo a projections.property ele vai tentar setar na Cliente cada field (setCdFilial…) e se for assim ele não se acha…

M
von.juliano:
Me desculpe, não havia notado um detalhe, os valores vem nulos por causa do ResultTransformer. Crie o seu próprio que os valores serão setados corretamente:
public class ClienteTransformer implements ResultTransformer {

	public List transformList(List list) {
		return list;
	}

	public Object transformTuple(Object[] values, String[] aliases) {
		Cliente c = new Cliente();
		ClienteId id = new ClienteId();
		id.setRg((String)values[0]);
		id.setCpf((String)values[1]);
		
		c.setId(id);
		return c;
	}
}
Vê se agora resolve! :D

Vou duplicar o post... Verdade! estava penssando em fazer isso mesmo... vou testar ... tnks...

[Editado] eu faço isso para cada valor entao?
id.setRg((String)values[0]);
id.setCpf((String)values[1]);
O

maniacs, quando falei em filtrar, eu quis dizer a WHERE do select. Filtro pra mim é quando você, por exemplo, faz um select retornando todos os nomes que começam com a letra X.

Projection não faz parte do filtro.

V

maniacs:
eu faço isso para cada valor entao?

id.setRg((String)values[0]); id.setCpf((String)values[1]);


Sim, como o hibernate vai te trazer um array de objects, você tem que definir na mão onde vai cada valor. Talvez exista uma forma melhor, acho que vou pesquisar isso :smiley:

Flw! :thumbup:

M

von.juliano:
maniacs:
eu faço isso para cada valor entao?

id.setRg((String)values[0]); id.setCpf((String)values[1]);


Sim, como o hibernate vai te trazer um array de objects, você tem que definir na mão onde vai cada valor. Talvez exista uma forma melhor, acho que vou pesquisar isso :smiley:

Flw! :thumbup:

To fazendo para ele usar reflect assim faz automatico… no momento vou deixar um a um para poder passar para os outros problemas… mas ja comecei algumas coisas com reflect

[Editado]
A Criteria ficou assim:

Criteria c = getSession().createCriteria(Cliente.class,"c");
        
        c.add(Restrictions.and(Restrictions.eq("clientePK.cdFilial", cdFilial), Restrictions.eq("cdVendedor", cdVendedor)));

        c.createAlias("c.municipio", "m");
        c.createAlias("c.cdEstado", "e");

        ProjectionList list = Projections.projectionList();
        list.add(Projections.property("c.clientePK.cdCliente"));
        list.add(Projections.property("c.clientePK.cdFilial"));
        list.add(Projections.property("c.nmCliente"));
        list.add(Projections.property("c.nmComprador"));
        list.add(Projections.property("c.dsEndcli"));
        list.add(Projections.property("c.nrEndcli"));
        list.add(Projections.property("c.dsBaicli"));
        list.add(Projections.property("c.cdCepcli"));
        list.add(Projections.property("e.cdEstado"));
        list.add(Projections.property("m.municipioPK.cdMunicipio"));
        list.add(Projections.property("m.dsMunicipio"));
        c.setProjection(list);

e claro, criei um ClienteTransformer como foi citado… obrigado pessoal!

Criado 10 de fevereiro de 2009
Ultima resposta 11 de fev. de 2009
Respostas 19
Participantes 3