Bom dia a todos, estou usando JPA para um projeto pequeno aqui na empresa e surgiu um necessidade de criar um sql de DELETE customizável então criei o seguinte SQL nativo que será executado pela JPA
String sql = "UPDATE sensores s SET id_particao=NULL "
+ "WHERE s.id_particao=?1";
///////////////////////
Query query = minhaEntityManager.createNativeQuery(sql, Sensor.class);
//parametros
query.setParameter(1, id_particao);
//Executo e mostro a resposta
System.out.println("Resultado final "+query.executeUpdate());
ao tentar executar o na última linha o seguinte erro ocorre
[quote]java.lang.IllegalStateException: You cannot call executeUpdate() on this query. It is the incorrect query type.
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.executeUpdate(EJBQueryImpl.java:528)
at persistence.SensorDAO.removerParticao(SensorDAO.java:186)
at persistence.ParticaoDAO.excluir(ParticaoDAO.java:97)…[/quote]
Queria saber se estou fazendo da maneira certa ou aonde estou errando?
Obs.: Uso EclipseLink e o código de SELECT roda dessa forma porém nunca tentei fazer com update nem delete, e pesquisando no google achei uma parte onde usava ‘ClassDescriptor’ porém não consegui implementa-la no meu código.
Também tentei somente removendo o ‘1’ que uso por causa de um bug do ‘LIKE’ do ‘SELECT’ porém o mesmo erro ocorre. Agora com o código que coloquei ai acima usando JPQL o erro muda para:
[quote]Exception Description: No transaction is currently active
at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionWrapper.throwCheckTransactionFailedException(EntityTransactionWrapper.java:113)
at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionWrapper.checkForTransaction(EntityTransactionWrapper.java:50)
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.checkForTransaction(EntityManagerImpl.java:1776)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.executeUpdate(EJBQueryImpl.java:533)
at persistence.SensorDAO.removerParticao(SensorDAO.java:187)…[/quote]
Estou tentando outras combinações aqui. Se souber mais alguma coisa avisa aí, flw!
Beleza lele_vader agora o código que você me indicou estava certo procurei um pouco sobre o erro e foi preciso apenas adicionar 2 linhas, 1 antes de realizar o update e 1 depois para finalizar a transação, ficando assim o código final:
String jpql = "UPDATE Sensor s SET s.idParticao = :novoid "
+ "WHERE s.idParticao = :particao";
///////////////////////
Query q = minhaEntityManager.createQuery(jpql, Sensor.class);
//parametros
q.setParameter("novoid", null);
q.setParameter("particao", meuObjetoParticao);
///
minhaEntityManager.getTransaction().begin(); //iniciar transação
System.out.println("Resultado final "+q.executeUpdate());
minhaEntityManager.getTransaction().commit(); //salvar estado
Para criar a meu EntityManager uso uma classe genérica que possui os métodos CRUD inclusive o de instanciar a EntityManager, caso personalize que nem agora crio outra classe que herde dessa, o método que uso é representado abaixo:
public EntityManagerFactory getEMF() throws Exception{
try{
if (emf == null || !emf.isOpen()) {
emf = Persistence.createEntityManagerFactory("AppDesktopGerenciaPU");
}
return emf;
}catch(Exception e){
Logger.getLogger(BaseDAO.class.getName()).log(Level.SEVERE, null, e);
throw new Exception(Mensagens.erroConectarBanco);
}
}
depois só o chamo caso for realizar alguma transação
[code]protected EntityManager em;
em = getEMF().createEntityManager();
[/code]
Outra coisa do modo que estou usando já não está fazendo a concatenação?
A entityManagerFactory só precisa ser instanciada uma vez.
Não precisa a cada transação recriá-la, precisa pegar é a entityManager, igual você faz em createEntityManager()
O seu projeto é web, usa spring ?
Porque se sim não precisa fazer isso que o spring gerencia isso para você, ou se estiver usando um ejb.
[quote=lele_vader]A entityManagerFactory só precisa ser instanciada uma vez.
Não precisa a cada transação recriá-la, precisa pegar é a entityManager, igual você faz em createEntityManager()
O seu projeto é web, usa spring ?
Porque se sim não precisa fazer isso que o spring gerencia isso para você, ou se estiver usando um ejb.
[/quote]
Então estou mexendo com um projeto Java Desktop ao chamar minha instância eu chamo o método getEmf() que está na minha classe genérica BaseDao lá também tem 2 objetos que são
e guardo as instancias lá porém sempre fecho a conexão no finally e recrio-a caso for usa-la novamente. As vezes também deixo um atributo booleano que representa se eu quero ou não fechar a conexão caso ‘false’ não fecho a conexão reaproveitando a conexão já aberta.
[quote=lele_vader]Depois conserta umas coisas.
1- Tirar concatenação de string no sql.
Coloca assim:
StringBuilder sql = new StringBuilder();
sql.append(""UPDATE Sensor s SET s.idParticao = :novoid");
sql.append("WHERE s.idParticao = :particao");
Query q = minhaEntityManager.createQuery(sql.toString(), Sensor.class);
[/quote]
Isto é desnecessário. O próprio compilador fará isso. Alias, não tendo nenhuma variável na String, é mais eficaz deixar o + do que usar o append, já que o compilador tratará como uma única String e não precisa de StringBuilder.