[RESOLVIDO] JPA - Obter chave gerada por Sequence em Trigger

29 respostas
P

Olá pessoal, blz?

Estou com um ‘probleminha’ aqui que está me enchendo… Tenho uma entidade ‘Pai’ e uma entidade ‘Filha’ (nomes fictícios) que possuem relacionamento 1 para N. A entidade Pai está mapeado para uma tabela no banco que possui uma Trigger (Before Insert - Oracle) que gera a chave primária automaticamente (buscando de uma sequence) … Porém, ao inserir um registro, a JPA não pega o ID gerado pela sequence na Trigger e sim um novo que ela mesma busca (fazendo select na sequence). O que resulta em um:

ORA-02291: restrição de integridade ... violada - chave mãe não localizada

ao inserir as entidades filhas. Ou seja, o registro inserido fica com um valor de ID e a entidade Pai fica com outro valor de ID.

Segue o código para analisarem:

@Entity
@Table(name = "PAI")
@SequenceGenerator(name = "PaiSeq", sequenceName = "PAI_SQ", allocationSize = 1)
public class Pai implements Serializable {

    @Id
    @Column(name="ID_PAI", nullable = false)    
    @GeneratedValue(generator="PaiSeq", strategy = GenerationType.SEQUENCE)
    private long id;

   @OneToMany(mappedBy="pai", fetch = FetchType.LAZY)
    private List<Filho> filhos;

//gets, sets etc.
}

Como já devem imaginar, isso não é negociável com os DBA’s.Portanto, tenho que me virar. Alguma luz?

Obrigado!

29 Respostas

L

Pode-se primeiro persistir o pai e depois setar os filhos e “merdiar” o pai novamente.

L

Li novamente e agora entendi a sua dúvida…pensando rs…

P

É justamente isso que estou fazendo.

Paz e bem!

P

Ah tá. rsrsrs…

Paz e bem!

L

humnn dexo ver, se você antes de persistir utilizar a sequence X que gera o nº 1, somente para que o provedor de persistencia não reclame da ausência do ID, na trigger ele ira gerar outro número para a chave com a sequence, terminando com o seu objeto pai após a persistencia com a sequence da trigger, se após isso você setar a List de filhos na pai e dar merge, a chave estrangeira da tabela pai na tabela de filhos não estara correta?

L

ou o objeto pai após a persistencia ficou com um ID nº1 e não o da trigger?

Qual situação esta ocorrendo?

P

Pois é mas, para isso eu teria que fazer uma chamada a classe de persistência só para fazer merge. Quando mando persistir, meu objeto já está pronto (inclusive com os filhos preenchidos). Até poderia fazer um ‘cascade’ ao fazer o INSERT mas, ocorre o mesmo erro (já testei).

Paz e bem!

P

Laubstein:
ou o objeto pai após a persistencia ficou com um ID nº1 e não o da trigger?

Qual situação esta ocorrendo?

Isso, o objeto Pai está ficando com o primeiro ID e não o gerado pela Trigger.

Paz e bem!

L

Entendi, não vejo outra saída cara, eu faria a persistencia do Pai, com o List de filhos nulo e depois os preencheria e realizaria mais uma chamada para o merge.

Vamos esperar se mais ninguém pode nos ajudar.

Abraço!

P

Laubstein:
Entendi, não vejo outra saída cara, eu faria a persistencia do Pai, com o List de filhos nulo e depois os preencheria e realizaria mais uma chamada para o merge.

Vamos esperar se mais ninguém pode nos ajudar.

Abraço!

É, eu não posso fazer isso pois essa entidade é resultado de um cálculo (que pode não dar certo) que gera esses filhos. Não faz sentido gravar antes de saber se está ok. Pelo menos pro meu caso. Mesmo assim, valeu d+ a ajuda! :thumbup:

Mais alguém?! :roll:

Paz e bem!

L

Entendi, achei que ele ficava com o da trigger, ai realmente fud@@ de vez … rsrs

Uma vez que tentar recuperar novamente o objeto você não poderá contar com o valor atual da sequence, já que alguém pode estar a modificando, a não ser que você crie um mecanismo para poder recupera-la sem erros, bem isso é gambi rs.

L

Mas até ai desacopla-los e depois acopla-los não é um problema e sim a sequence :stuck_out_tongue:

L

Já que existe uma trigger que inclui o ID automaticamente na tabela, por que você não configura este ID como uma coluna de auto incremento, já testou isto?

@Id  
   @Column(name="ID_PAI", nullable = false)      
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   private long id;

flw

A

É Oracle e o sequence já é auto incremento…

via SQL: (insert…minha_sequence.NEXTVAL).

Este comendo pode ser utilizado tanto para inserir quanto para saber qual o próximo ID.

Espero ter ajudado de alguma forma.

L

alexlima72:
É Oracle e o sequence já é auto incremento…

via SQL: (insert…minha_sequence.NEXTVAL).

Este comendo pode ser utilizado tanto para inserir quanto para saber qual o próximo ID.

Espero ter ajudado de alguma forma.

Acredito que todos aqui saibam disto, mas você leu qual é o motivo do problema? Que existe uma trigger que insere o ID antes do insert ser executado.

flw

L

AUTO, deixará o provedor escolher a melhor estrategia para o banco de dados inferior, no caso se for o oracle provavelmente a escolha é SEQUENCE.

L

lap_junior:
Já que existe uma trigger que inclui o ID automaticamente na tabela, por que você não configura este ID como uma coluna de auto incremento, já testou isto?

@Id  
   @Column(name="ID_PAI", nullable = false)      
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   private long id;

flw

Acabei copiando errado, não AUTO mas sim IDENTITY. Isso porque com esta trigger esta coluna funciona como se fosse autoincremento.

L

Não lembro se Oracle suportam colunas de identidade… tem de testar.

L

Acho que não, de qualquer forma acho que o problema continuaria.

P

lap_junior:
lap_junior:
Já que existe uma trigger que inclui o ID automaticamente na tabela, por que você não configura este ID como uma coluna de auto incremento, já testou isto?

@Id  
   @Column(name="ID_PAI", nullable = false)      
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   private long id;

flw

Acabei copiando errado, não AUTO mas sim IDENTITY. Isso porque com esta trigger esta coluna funciona como se fosse autoincremento.

O Oracle não suporta colunas IDENTITY. Isso é usado no SQL Server e outros…

Paz e bem!

P

anyone? :roll:

L

Putz ainda nada T_T, tentou outras alternativas cara? Posta aí para discutirmos.

L

Nessa mesma tabela, você grava um campo TimeStamp?

P

questão complicada, considere estender o hibernate e criar sua própria estratégia de geração de sequence.

L

O.o rs

P

É pessoal, fui ver com uns colegas aqui e eles tiveram que usar um GenericGenerator (que herda de AbstractPostInsertGenerator e implementa Configurable) para resolver o problema. Ou seja, dentro do Generator faz-se um ‘select curval’ da vida… Vale lembrar que o GenericGenerator é Hibernate e não JPA.

@Entity  
@Table(name = "PAI")  
public class Pai implements Serializable {  

@Id  
@Column(name="ID_PAI", nullable = false)      
@GeneratedValue(generator="PaiSeq")
@GenericGenerator(name = "PaiSeq", strategy = "br.com.guj.GeneratorTabajara", parameters = { @Parameter(name = "sequence", value = "PAI_SQ") })
private int id;  
   
@OneToMany(mappedBy="pai", fetch = FetchType.LAZY)  
private List<Filho> filhos;  

//gets, sets etc.  
}

Bom, está aí. Boa pedida para o JPA na próxima versão pois, ninguém merece ficar criando ‘workarrounds’…

Paz e bem!

P

Justo.

P

Olá pessoal, blz?

Como me procuraram afim de sabem qual solução eu havia usado, passo o link de um post no fórum do Hibernate com a solução: https://forum.hibernate.org/viewtopic.php?p=2379010

Valeu!

F

acredito que a dica do rapaz ali que disse pra usar IDENTY funcionaria, pois a trigger esta simulando um campo AUTO_INCREMENT. Tive um problema semelhante aqui, facilitei a vida de todos, e utilizei a estrategia SEQUENCE e deletei as triggers.

Na verdade, acho esse lance de usar trigger pra gerar ID, uma verdadeira gambiarra

Criado 13 de novembro de 2009
Ultima resposta 25 de ago. de 2014
Respostas 29
Participantes 6