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
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.
Tira o “1” aí após o ?
Essa consulta não dá para ser feito com jpql não ?
Para que nativeQuery. É só um update.
I
Ivan_Alves
Então lele_vader obrigado pela resposta na minha alteração ficou dessa forma
Stringjpql="UPDATE Sensor s SET s.idParticao = :novoid "+"WHERE s.idParticao = :particao";///////////////////////Queryq=minhaEntityManager.createQuery(jpql,Sensor.class);//parametrosq.setParameter("novoid",null);q.setParameter("particao",meuObjetoParticao);///System.out.println("Resultado final "+q.executeUpdate());
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:
Estou tentando outras combinações aqui. Se souber mais alguma coisa avisa aí, flw!
L
lele_vader
Esse erro já é diferente.
Ele diz que não tem transação ativa.
Como você instancia o entityManager ?
Está usando ejb ?
Outra coisa, não use concatenação de string em sql. Pode permitir sql injection.
Use stringbuilder e o método append para isso.
I
Ivan_Alves
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
Vlw demais ajudou muito, bom fim de semana!
L
lele_vader
Calma ai.
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);
2-Colocar rollback em catch e finally fechar o entityManager, considerando que você não está usando um ejb para fazer isso para você.
I
Ivan_Alves
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:
depois só o chamo caso for realizar alguma transação
protected EntityManager em;
em = getEMF().createEntityManager();
Outra coisa do modo que estou usando já não está fazendo a concatenação?
I
Ivan_Alves
Vou mostrar o código por completo com algumas alterações propostas, me corrija caso haja algum erro:
public void removerParticao(Particao particao) throws Exception{
em = getEMF().createEntityManager();
try {
StringBuilder jpql = new StringBuilder();
jpql.append("UPDATE Sensor s SET s.idParticao = :novoid ");
jpql.append("WHERE s.idParticao = :particao");
///////////////////////
Query q = em.createQuery(jpql.toString(), Sensor.class);
//parametros
q.setParameter("novoid", null);
q.setParameter("particao", particao);
///
em.getTransaction().begin();
System.out.println("Resultado final "+q.executeUpdate());
em.getTransaction().commit();
} catch (Exception e) {
try{
em.getTransaction().rollback();
}catch(Exception ex){}
Logger.getLogger(BaseDAO.class.getName()).log(Level.SEVERE, null, e);
throw new Exception(Mensagens.erroRemoverParticaoDoSensor);
} finally {
em.close();
emf.close();
}
}
flw!
L
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.
I
Ivan_Alves
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.
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.
L
lele_vader
Ah.Não tinha visto.
Então o entityManagerFactory você não precisa fechar.
O seu método getEMF pode ver se o entityManagerFactory é null.
Se sim você o cria, senão só retorna o já existente.
P
pmlm
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);
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.
L
lele_vader
Se você concatenar string a cada string concatenada ele cria outra.
String é imutável.
P
pmlm
Não disse nada que contrariasse isso. Simplesmente neste caso concreto o StringBuilder não só não é melhor como é mesmo pior do que usar String.