[Resolvido] Hibernate Composite ID Projections

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:

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

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:

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

Então não deveria ser algo assim?

[code]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));  [/code]

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.

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

[code]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());[/code]

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.

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

Fiz um teste aqui e consegui fazer da seguinte forma:[code]
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));[/code]O “id” é uma classe ClienteId com rg e cpf.

Vê se te ajuda! Flw! :thumbup:

[quote=von.juliano]Fiz um teste aqui e consegui fazer da seguinte forma:[code]
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));[/code]O “id” é uma classe ClienteId com rg e cpf.

Vê se te ajuda! Flw! :thumbup: [/quote]

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…

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

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

Quando usamos composite key dá pra fazer isso:

[code]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()); [/code]

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.

[quote=otavio]Quando usamos composite key dá pra fazer isso:

[code]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()); [/code]

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.[/quote]

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!

[quote=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! [/quote]

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.

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:

[code]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;
}

}[/code]
Vê se agora resolve! :smiley:

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…

[quote=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:

[code]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;
}

}[/code]
Vê se agora resolve! :smiley: [/quote]

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]);

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.

[quote=maniacs]eu faço isso para cada valor entao?

id.setRg((String)values[0]); id.setCpf((String)values[1]); [/quote]
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:

[quote=von.juliano][quote=maniacs]eu faço isso para cada valor entao?

id.setRg((String)values[0]); id.setCpf((String)values[1]); [/quote]
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: [/quote]

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!