PERSIST RELACIONAL (1 x N) EM 5 PASSOS

Pessoal, estou postando este tópico para levantar uma questão:

Qual a melhor maneira de persistir objetos relacionados.

Considero como PASSOS neste processo as principais ETAPAS, desconsiderando o que é trivial.
Tenho o seguinte modulo no sistema:

Cadastro de fórmulas.
Cadastro de atributos de uma fórmula.
Cadastro de sub fórmulas.

Uma fórmula tem muitos atributos e muitas sub formulas ok.

Para esta situação eu criei a seguinte rotina em minha action (salvarFormula) :

1º Crio uma nova fórmula (Objeto principal do negócio) . (PASSO 1)

2º Crio uma lista de atributos e insiro os atributos da fórmula. (PASSO 2.0)

3º Crio uma lista de subFormulas e insiro as subFormulas da fórmula. (PASSO 2.1 [PROCESSO IDENTICO PASSO 2.0])

4º Crio um método DAO salvarFormula e envio como parametro a fórmula e os lists: atributoS, subFormulaS (3 parametros). (PASSO 3)
---- Neste método inicio a transação
---- persisto a formula (PASSO 4)
---- em loop persisto atributo por atributo ( só neste momento (interação por interação) vinculo a fórmula ao atributo ) (PASSO 5.0)
---- em loop, faço o mesmo com as subformulas (PASSO 5.1)
---- fecho a transação

Notas :
---- Obtive erro quando vinculei a formula aos atributos antes da iteração (laço) pois o objeto formula ainda não estava persistido.
---- Não usei cascades para persistir os dados

Perguntas :
Alguem dá preferencia pelo cascade ? por que ?
Este é o melhor modelo de persistir objetos relacionados ? Sim/Não porquê ?

METODO DAO

/** SALVA FORMULA E ATRIBUTOS E FORMULAS MES **/
	public void salvar(RgFormula rgFormula, 
						Collection<RgFormulaAtributo> rgFormulaAtributoS, 
						Collection<RgFormulaMes> rgFormulaMesS) {
		
		Transaction tx = session.beginTransaction();
		
		try{
			
			session.persist(rgFormula); // PERSISTE FORMULA (OBJ PRINCIPAL)
			
			if(rgFormulaAtributoS.size()>0){ // SALVA ATRIBUTOS
				
				for (RgFormulaAtributo rgFormulaAtributo : rgFormulaAtributoS) {
					
					rgFormulaAtributo.setRgFormula(rgFormula);
					
					session.persist(rgFormulaAtributo);
					
				}
				
			}
			
			if(rgFormulaMesS.size()>0){ // SALVA FORMULA MES
				
				for (RgFormulaMes _rgFormulaMes : rgFormulaMesS) {
						
					_rgFormulaMes.setRgFormula(rgFormula);
					
					session.persist(_rgFormulaMes);
					
				}
				
			}

			tx.commit();
			
		}catch (Exception e) {

			EeMail.sEmailAdm("ERRO NO CADASTRO DE FÓRMULAS",e.getMessage());
			
			e.printStackTrace();
			
			tx.rollback();
			
		}
		
	}

[]s
Jsign

Eu uso o hibernate pra trazer facilidades então eu deixo ele fazer todo o trabalho, uso cascade!

Legal Pbnf, obrigado pela sua opnião.

Será que poderia demonstrar como ficaria este método DAO usando o Cascade.

Pra ser sincero eu já tenho o metodo pronto, mas optei por não usar cascade neste caso.

Gostaria de comparar com o seu modelo.

[]s
Jsign

Faço via anotação no modelo de dados mas acho que pode ser feito tbm no momento do HQL ou do Criteria, e quanto ao codigo tudo é subjetivo então desencana em ficar comparando com outros codigos.

Olá Pbnf,

Eu uso annotations @Cascade mas em outros casos.

@Cascade({org.hibernate.annotations.CascadeType.PERSIST,org.hibernate.annotations.CascadeType.MERGE})

O exemplo aqui postado demonstra duas entidades que poderiam persistir a Formula, ou seja, tanto a FormulaAtributo quanto a FormulaMes poderiam ter anotações para persistir a Fórmula.

Mas qual delas iria persistir o objeto Formula, sendo que ambas estão sobre a mesma transação ? R: Possívelmente o primeiro objeto a ser persistido.

Se for assim, o segundo objeto a ser persistido já teria uma referência existente e “persistida” correto ? R: Sim.

Mas estamos em uma rotina transacional então não necessáriamente estão persistidos os objetos correto ? R: Sim, eu acho que é po!!!

Pensando em desenvolvimento coletivo, eu prefero não utilizar cascades quando o pai a ser persistidos tem diferentes tipos de filhos ex:

PaiCarro
----- FilhoMotor
----- FilhoRoda (@cascade salva e atualiza pai)
----- FilhoVolante (@cascade salva e atualiza pai)
------ …

Agora imagine a rotina:
transacao > salva motor > salva roda, salva volante

Quem salvou ou atualizou o carro afinal, e se eu estiver só atualizando a roda/volante ?
E o motor que foi o primeiro a ser persistido e não persitiu o Pai ? Será que vai dar pau, mesmo que a proxima iteração o crie ?

Para casos assim prefiro não usar cascades, pois não tenho como privilegiar um filho a salvar o pai de vários filhos.
Prefiro ter controle da classe principal.
Não é crítica a engine de persistencia, que é fantástica. Mas acho que estou preservando a “LEITURA DO CÓDIGO”.
Uso Cascades de persistencia para Pais de um filho ou dois no máximo.

Pense em você olhando para um código desenvolvido por outra pessoa.

" Po, se eu quero salvar um Carro, mando salvar a Roda ! Estranho .
Hunnn, o camarada está usando cascade. Mas em quais filhos ?
Puts, melhor tomar cuidado. ".

Na rotina vista você manda salvar um FilhoMotor e seta neste o PaiCarro, mas o pai carro não está persistido, e o FilhoMotor não pode persisti-lo.

Porem na mesma transação, mas no laço posterior, você tem um filho que pode persistir o pai, a roda.

Será que vai dar certo?

Exemplo:


tx = transacao.begin

for(FilhoMotor fm : motoreS){

session.persist(fm); // nao salva Carro // mas tem um carro novo apontado em seu setPaiCarro [ transiente value ]

}

for(FilhoRoda fr : rodaS){

session.persist(fr); //salva Carro // será que atualiza a referencia do objeto PaiCarro no motor ?

}

tx.commit

[color=blue]
Bom, o erro ocorre no primeiro for porque um motor não pode salvar PaiCarro.
Só que se você trocar a ordem das iterações, tudo vai dar certo, pois o PaiCarro foi criado na criação de uma roda persitida.

Há, mas quem mandou o desenvolvedor não colocar na ordem certa ou porque não colocou o cascade também no motor.[/color]

Valeu Pbnf, mas é importante deixar aqui que usar cascades é ótimo mas deve ser visto de n aspéctos.

[]s
Jsign

Olá Pbnf,

Eu uso annotations @Cascade mas em outros casos.

@Cascade({org.hibernate.annotations.CascadeType.PERSIST,org.hibernate.annotations.CascadeType.MERGE})

O exemplo aqui postado demonstra duas entidades que poderiam persistir a Formula, ou seja, tanto a FormulaAtributo quanto a FormulaMes poderiam ter anotações para persistir a Fórmula.

Mas qual delas iria persistir o objeto Formula, sendo que ambas estão sobre a mesma transação ? R: Possívelmente o primeiro objeto a ser persistido.

Se for assim, o segundo objeto a ser persistido já teria uma referência existente e “persistida” correto ? R: Sim.

Mas estamos em uma rotina transacional então não necessáriamente estão persistidos os objetos correto ? R: Sim, eu acho que é po!!!

Pensando em desenvolvimento coletivo, eu prefero não utilizar cascades quando o pai a ser persistidos tem diferentes tipos de filhos ex:

PaiCarro
----- FilhoMotor
----- FilhoRoda (@cascade salva e atualiza pai)
----- FilhoVolante (@cascade salva e atualiza pai)
------ …

Agora imagine a rotina:
transacao > salva motor > salva roda, salva volante

Quem salvou ou atualizou o carro afinal, e se eu estiver só atualizando a roda/volante ?
E o motor que foi o primeiro a ser persistido e não persitiu o Pai ? Será que vai dar pau, mesmo que a proxima iteração o crie ?

Para casos assim prefiro não usar cascades, pois não tenho como privilegiar um filho a salvar o pai de vários filhos.
Prefiro ter controle da classe principal.
Não é crítica a engine de persistencia, que é fantástica. Mas acho que estou preservando a “LEITURA DO CÓDIGO”.
Uso Cascades de persistencia para Pais de um filho ou dois no máximo.

Pense em você olhando para um código desenvolvido por outra pessoa.

" Po, se eu quero salvar um Carro, mando salvar a Roda ! Estranho .
Hunnn, o camarada está usando cascade. Mas em quais filhos ?
Puts, melhor tomar cuidado. ".

Na rotina vista você manda salvar um FilhoMotor e seta neste o PaiCarro, mas o pai carro não está persistido, e o FilhoMotor não pode persisti-lo.

Porem na mesma transação, mas no laço posterior, você tem um filho que pode persistir o pai, a roda.

Será que vai dar certo?

Exemplo:


tx = transacao.begin

for(FilhoMotor fm : motoreS){

session.persist(fm); // nao salva Carro // mas tem um carro novo apontado em seu setPaiCarro [ transiente value ]

}

for(FilhoRoda fr : rodaS){

session.persist(fr); //salva Carro // será que atualiza a referencia do objeto PaiCarro no motor ?

}

tx.commit

[color=blue]
Bom, o erro ocorre no primeiro for porque um motor não pode salvar PaiCarro.
Só que se você trocar a ordem das iterações, tudo vai dar certo, pois o PaiCarro foi criado na criação de uma roda persitida.

Há, mas quem mandou o desenvolvedor não colocar na ordem certa ou porque não colocou o cascade também no motor.[/color]

Valeu Pbnf, mas é importante deixar aqui que usar cascades é ótimo mas deve ser visto de n aspéctos.

[]s
Jsign