Possuo um projeto que possui uma classe Cliente, Produto e Compra onde em uma tabela mysql possui um relacionamento que n:n entre produto e compra (que se cria a tabela compraproduto).
na minha CompraDAO estou tentando fazer uma consulta para listar todos os produtos que estão inseridos em uma determinada compra
public List<Produto> carregarCarrinho(Compra compra){
List<Produto> listaProduto;
Session session = HibernateUtil.getSessionFactory().openSession();
String sql = "from Produto p, compraproduto cp where idCompra = 1 and p.idProduto = cp.idProduto";
//String sql = "from Produto p join p.compraproduto cp where cp.idCompra = :id and p.idProduto = cp.idProduto";
listaProduto = session.createQuery(sql).setParameter("id", compra.getIdCompra()).list();
session.close();
return listaProduto;
}
Porém ele dá a mensagem que compraproduto não está mapeado
Advertência: #{cadastroCompraBean.selecionaCompra()}: org.hibernate.hql.internal.ast.QuerySyntaxException: compraproduto is not mapped [from modelo.Produto p, compraproduto cp where idCompra = 1 and p.idProduto = cp.idProduto]
como compraproduto é o nome da tabela do relacionamento entre duas tabelas, não foi criado uma classe para ela. Como faço para mapear ou teria alguma outra maneira de fazer esse tipo de consulta.
Voce está usando hibernate, a forma de chamar com hibernate é bem diferente do sql normal, por isso é chamado de HQL, no hibernate você pode fazer essas query usando Criteria ou então usando namedQuery, recomendo você a procurar na internet exemplos de DAO no hibernate que já vem até com o código de insert, update, remove, etc. Geralmente em uma classe do tipo controller. Abaixo vai exemplo do meu código que uso, lembrando que a classe VoidDAO é abstrata para não ter que ficar copiando código repetido toda hora, e a ClienteDAO implementa os códigos necessários para chamar insert, remove, update, pesquisa por id, e todos os metodos com anotação @Override são específicos da classe cliente.
public abstract class VoidDAO<T> {
private EntityManager entityManager;
public VoidDAO(EntityManager em) {
this.entityManager = em;
entityManager.getTransaction().begin();
}
public void salvar(T objeto) {
this.entityManager.persist(objeto);
commit();
}
public void alterar(T objeto) {
this.entityManager.merge(objeto);
commit();
}
public void remover(T objeto) {
this.entityManager.remove(this.entityManager.merge(objeto));
commit();
}
public void fechar(){
entityManager.close();
}
public void commit() {
if (this.entityManager == null) {
return;
}
if (this.entityManager.getTransaction().isActive()) {
this.entityManager.getTransaction().commit();
}
}
public void rollBack(){
if (this.entityManager == null) {
return;
}
if (this.entityManager.getTransaction().isActive()) {
this.entityManager.getTransaction().rollback();
}
}
/**
*
* @param namedQuery
* @return
*/
public List<T> getListaCompleta(String namedQuery) {
Query query = this.entityManager.createNamedQuery(namedQuery);
List<T> object=(List<T>) query.getResultList();
rollBack();
return object;
}
public T findById(Class<T> classe, Integer id) {
T objeto=(T) this.entityManager.find(classe, id);
rollBack();
return objeto;
}
@Entity @Table(name = “compra”) @XmlRootElement @NamedQueries({ @NamedQuery(name = “Compra.findAll”, query = “SELECT c FROM Compra c”)
, @NamedQuery(name = “Compra.findByIdCompra”, query = “SELECT c FROM Compra c WHERE c.idCompra = :idCompra”)
, @NamedQuery(name = “Compra.findByData”, query = “SELECT c FROM Compra c WHERE c.data = :data”)})
public class Compra implements Serializable {
Nesses dois exemplos acima mostra primeiro como conseguir uma lista e no outro como passar o parâmetro para a @NamedQuery que é feita na sua classe. No hibernate não é bom usar SQL, sempre da algum erro, por isso ele tem as alternativas que ele mesmo mapeia. Eu vi que você já tem uma @NamedQuery igual ao da sua pesquisa, é só substituir pelas do meu exemplo.
Discordo.
Embora a API Criteria seja muito boa, tem coisas que ficam muito mais fáceis quando rodamos com HQL.
Além disso, se o conhecimento sobre Criteria ou HQL é limitado, sempre é possível utilizar Native Queries.
Todas as query feitas em SQL da para fazer com HQL, no caso da query que ele fez de SQL, ele já tinha uma NamedQuery pronta igual aquela, que era fácil de usar e concerteza usando menos código. Utilizar o HQL ajuda a errar menos e fica mais fácil do hibernate achar. Se você fizer a mesma consulta em uma base de dados grande no hibernate uma usando SQL e a outra usando HQL você vai verificar que a que está em HQL vai retornar mais rápido. Por isso eu disse que não é bom usar SQL, não que era proibido.
Criteria/HQL gera SQL, como SQL vai ser mais rápido do que SQL? Só se a pessoa não souber SQL direito e fazer besteira.
Não vem ao caso, mas ambas as formas com Hibernate são ruins em consumo de recursos. Quanto mais engenhocas no meio do caminho mais recursos vai consumir.
é que o hibernate já mantém cache com os recursos dele, instancias a objetos, facilitando o retorno, além de ter vários recursos que integram bem com java, pois a pesquisa não é só ir no banco, mas também colocar seus valores em variáveis. Eu já fiz o teste aqui para saber se havia diferença ao usar o hibernate com SQL ou com HQl, e vi que tinha. Além do que o hibernate já vem com alguns tratamentos de erro que você tem que fazer manual se usar apenas o SQL, hibernate tem drivers específicos de integração com vários bancos e tem melhor portabilidade se por um acaso você precisar mudar por exemplo do MySQL pro Postegre. Com Hibernate diminui quantidade de código da aplicação(isso quando programas comerciais que são maiores). SQL nativo é bom apenas para trabalhos pequenos de faculdade, no Hibernate você acha mais fácil exemplos de utilização de diversos recursos principalmente de novos e no SQL normal você custa a achar coisas prontas. Se quiser saber mais diferenças entre os 2 ai é só procurar na internet.
Tudo isso custa processamento e memória, principalmente o session factory. Isso não é necessário para o resultado na maioria das aplicações atuais (back-end HTTP). Não é eficiente ir até o servidor para acessar cache, que deveria estar no próprio client (navegador ou app). Lazy é outro recurso inútil para HTTP. Para legados desktop concordo que o custo do hibernate traz retornos.
SQL sempre foi bem difundido e não se limita ao mundo do programador Java. Se o profissional depende de coisas prontas é por que não sabe SQL. Sei que JDBC puro é improdutivo, mas existem meios termos como JDBCTemplate da Spring, que é mais leve do que jpa/hibernate, trazendo somente o que é necessário para atender requisições sem estado, como é o exemplo de HTTP.