Futucando JPA, hj me deparei com uma situação que me deixou intrigado.
Exemplo:
Tenho uma entidade chamada CLIENTES com os atributos ID, Nome, Endereco e CPF
Pra eu rotornar uma lista dos clientes é tranquilo, mas se por exemplo quero puxar uma
lista só com ID e Nome, é possível? como?
Eu tentei aqui, mas só dá erro na construção do EntityManager.
//Tenho uma lista completa
em.createQuery("Select pj FROM PessoaJuridica pj).getResultList();
//Aqui queria selecionar algumas campos
em.createQuery("Select pj.ID, pj.Fantasia FROM PessoaJuridica pj).getResultList();
Algo mais ou menos assim.
A minha intensão é, ao abrir um cadastro de clientes e precisar fazer uma busca de
um cliente, abrir um JDialog com alguns campos, e carregar o objeto inteiro seria algo
iviável, no meu caso.
o método “getResultList()” retorna um List de Object,
e não da classe model que você está querendo.
Eu fiz alguns testes aqui, e quando tento selecionar alguns campos apenas, como você está fazendo,
ao fazer a iteração da lista de objetos que o JPA me traz, ele levanta uma ClassCastException, ou seja,
como o Object que ele retorna não possui o mesmo número nem os mesmos campos que a minha classe possui,
ele não consegue fazer o “casting”. Criei uma base de testes aqui , veja abaixo o que tentei fazer:
ASSIM LEVANTOU EXCEÇÃO:
[code]
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpa-hibernate");
EntityManager em = emf.createEntityManager();
Query query = em.createQuery("SELECT c.nmCliente, c.nrCnpj from Cliente c");
List <Cliente> list;
list = (List<Cliente>) query.getResultList();
em.close();
emf.close();
for(Cliente c : list)
System.out.println( "NOME CLIENTE: "+ c.getNmCliente()+ "CNPJ: "+c.getNrCnpj());
[/code]
ASSIM NÃO LEVANTOU EXCEÇÃO:
[code]
EntityManagerFactory emf = Persistence.createEntityManagerFactory("jpa-hibernate");
EntityManager em = emf.createEntityManager();
Query query = em.createQuery("SELECT c from Cliente c");
List <Cliente> list;
list = (List<Cliente>) query.getResultList();
em.close();
emf.close();
for(Cliente c : list)
System.out.println( "NOME CLIENTE: "+ c.getNmCliente()+ "CNPJ: "+c.getNrCnpj());[/code]
Pois é, aí fica então a questão: até onde vale a pena usar essas tecnologias?
Pq, se quero simplesmente trazer um ou dois campos de uma tabela com 20 campos, eu acabo
trafegando 18 campos em vão e dependendo do volume de dados, isso pode prejudicar
a performance, “sem sentido”.
E se você criar uma @NamedQuery dentro de sua entidade.
Tipo: @NamedQuery (name = “Proprietario.findAll”, query = “SELECT c.nmCliente, c.nrCnpj FROM cliente c”)
ola…
da para fazer sim… mas ai vc tem que transformar sua List num array de Objeto
e cada posição do array do Objeto retorna outro array de objeto, que correspondem aos atributos da sua consulta… entende???
exemplo:
List messages = em.createQuery("select m.id, m.text from Message m order by m.text asc").getResultList();
Object[] obj = messages.toArray();//transformar sua List num array de Objeto
Object[] o = (Object[]) obj[0];//cada posição do array do Objeto retorna outro array de objeto, peguei a pos 0
Long id = (Long) o[0];
String text = (String) o[1];
System.out.println("id : "+id+" text "+text);
console:
[code]
Hibernate:
/* select m.id,
m.text
from
Message m
order by
m.text asc */ select
message0_.MESSAGE_ID as col_0_0_,
message0_.MESSAGE_TEXT as col_1_0_
from
MESSAGES message0_
order by
message0_.MESSAGE_TEXT asc
No meu caso, o erro tá já na criação da consulta, ou seja, n consegui fazer como no seu exemplo.
List query = em.createQuery("Select t.ID, t.Descricao FROM Conta t").getResultList();
Object [] obj = query.toArray();
[code]
debug:
[TopLink Info]: 2009.01.12 03:44:55.011–ServerSession(28346522)–TopLink, version: Oracle TopLink Essentials - 2.0.1 (Build b09d-fcs (12/06/2007))
[TopLink Info]: 2009.01.12 03:44:55.568–ServerSession(28346522)–file:/media/ARQUIVOS/Projetos2009/Phenix/src/-PhenixPU login successful
Exception in thread “main” java.lang.IllegalArgumentException: An exception occured while creating a query in EntityManager
at oracle.toplink.essentials.internal.ejb.cmp3.EntityManagerImpl.createQuery(EntityManagerImpl.java:209)
at phenix.Main.main(Main.java:51)
Caused by: Exception [TOPLINK-8030] (Oracle TopLink Essentials - 2.0.1 (Build b09d-fcs (12/06/2007))): oracle.toplink.essentials.exceptions.EJBQLException
Exception Description: Error compiling the query [Select t.ID, t.Descricao FROM Conta t], line 1, column 16: unknown state or association field [Descricao] of class [br.com.yeld.phenix.entidade.Conta].
at oracle.toplink.essentials.exceptions.EJBQLException.unknownAttribute(EJBQLException.java:474)
at oracle.toplink.essentials.internal.parsing.DotNode.validate(DotNode.java:101)
at oracle.toplink.essentials.internal.parsing.SelectNode.validate(SelectNode.java:329)
at oracle.toplink.essentials.internal.parsing.ParseTree.validate(ParseTree.java:229)
at oracle.toplink.essentials.internal.parsing.ParseTree.validate(ParseTree.java:211)
at oracle.toplink.essentials.internal.parsing.ParseTree.validate(ParseTree.java:201)
at oracle.toplink.essentials.internal.parsing.EJBQLParseTree.populateReadQueryInternal(EJBQLParseTree.java:134)
at oracle.toplink.essentials.internal.parsing.EJBQLParseTree.populateQuery(EJBQLParseTree.java:108)
at oracle.toplink.essentials.internal.ejb.cmp3.base.EJBQueryImpl.buildEJBQLDatabaseQuery(EJBQueryImpl.java:219)
at oracle.toplink.essentials.internal.ejb.cmp3.base.EJBQueryImpl.buildEJBQLDatabaseQuery(EJBQueryImpl.java:189)
at oracle.toplink.essentials.internal.ejb.cmp3.base.EJBQueryImpl.buildEJBQLDatabaseQuery(EJBQueryImpl.java:153)
at oracle.toplink.essentials.internal.ejb.cmp3.base.EJBQueryImpl.(EJBQueryImpl.java:114)
at oracle.toplink.essentials.internal.ejb.cmp3.base.EJBQueryImpl.(EJBQueryImpl.java:99)
at oracle.toplink.essentials.internal.ejb.cmp3.EJBQueryImpl.(EJBQueryImpl.java:86)
at oracle.toplink.essentials.internal.ejb.cmp3.EntityManagerImpl.createQuery(EntityManagerImpl.java:204)[/code]
Foi mal…
Compilou, vou testar.
Mas q eh f… ficar trabalhando com objetos é, vai rolar muito box e uboxing na minha aplicação, pq
vou precisar muito de usar esse tipo de esquema.
Cara, tô acostumado com o C#, um caso desse eu faria assim:
//dc eh meu DataContext, algo como EntityManager
var query = (from c in dc.Conta
select new { c.ID, c.Descricao }).ToList();
foreach (var c in query)
........
//Aqui n preciso trabalhar com cast, os tipos são os definidos na classe.
//e posso usar a "query" como fonte de dados pra qq bagaça.
De vez em qdo a Microsoft acerta em alguma coisa *rrr, o LINQ e métodos anônimos foram um bom acerto.
Mas quero, “a todo custo” fazer esta minha aplicação em Java, quero me livrar da MS *r
Valeu a ajuda Felipe, qq coisa, posto aqui novamente.
Eu sei q “tudo” é objeto, mas qdo é tipado diminui trabalho e consome menos recursos.
Esta solução apresentada retornaria um List Object[] tb? Ele me pareceu mais limpa.
[quote=UpTheIrons]Eu sei q “tudo” é objeto, mas qdo é tipado diminui trabalho e consome menos recursos.
Esta solução apresentada retornaria um List Object[] tb? Ele me pareceu mais limpa.[/quote]
Retorna uma lista de ClienteDTO, portanto, dá pra fazer o cast para List. Teste e veja.
[quote=UpTheIrons]Opa, tava vendo sua solução, tenho reolhar o código pra entender *r.
Mas você tem sabe da performance desse modelo?[/quote]
Como vc está usando as Annotations de JPA, essa questão de carregar todos os dados sem necessidade, pode ser evitado usando LAZY. Dessa forma, o conteúdo só será trazido quando necessário.
Dá uma pesquisada sobre FetchType.LAZY e sobre Open Session in View, vc não terá problemas de performance, pois só usará o conteúdo que desejas, que neste caso é o codigo e o nome…