Bomba! DAO + Relacionamento 1..N

10 respostas
Thiago_Senna

Olá GUJ's

Pessoal, deu um nó na minha cabeça!
Tenho uma empresa que pode ter n serviços prestados. Persistir empresa até que é moleza, mas não sei qual seria a melhor maneira de persistir o serviço prestado.

Bom, considerando que o serviço prestado depende que uma empresa exista, eu poderia persistir utilizando uma destas abordagens.

1 -
ServicoPrestadoDAO servDao = new ServicoPrestadoDAO();
servDao.create(servico1);
servDdao.create(servico2);
empresa.addServicoPrestado(servico1);
empresa.addServicoPrestado(servico2);

EmpresaDAO empresaDAO = new EmpresaDAO();
empresaDAO.create(empresa);
ou assim: 2 -
empresa.addServicoPrestado(servico1);
empresa.addServicoPrestado(servico2);
EmpresaDAO empresaDAO = new EmpresaDAO();
empresaDAO.update(empresa);

Reparem que na segunda abordagem eu não precisei persistir o servico antes de utilizá-lo. Quando dou o empresaDAO.update(empresa) subtendo que ele seja capaz de perceber que o servico1 e servico2 devem ser persistidos, e ele já faz para mim este serviço!
Ele também deveria perceber caso eu deletasse algum servicoPrestado.!

A questão é saber qual é a abordagem mais conveniente! A 2 parace ser melhor, mas é? Como vcs fazem isso?

Vou postar aqui um código de teste unitário, talvez fique melhor de entender!

public void testCreateServicoPrestadoAPartirDaEmpresa() throws DAOException {
		Empresa empresa = new Empresa(new Cnpj("1"), "Empresa");
		dao.create(empresa);
		
		// criando servico prestado
		ServicoPrestado sp1 = new ServicoPrestado("Titulo1", "Descricao2");
		ServicoPrestado sp2 = new ServicoPrestado("Titulo2", "Descricao2");
		empresa.addServicoPrestado(sp1);
		empresa.addServicoPrestado(sp2);
		// os servicos prestados sao persistidos
		dao.update(empresa);
		
		empresa = null;
		empresa = dao.load(new Cnpj("1"));
		assertEquals(2, empresa.getServicoPrestado().size());
		assertTrue(empresa.getServicoPrestado().contains(sp1));
		assertTrue(empresa.getServicoPrestado().contains(sp2));		
	}

Abraços!
Thiago Senna

10 Respostas

louds

Só depende da sua boa vontade de implementar toda semântica de cascateamento das operações.

Thiago_Senna

louds:
Só depende da sua boa vontade de implementar toda semântica de cascateamento das operações.

Boa… eu nunca fiz isso.

É apenas um trabalho de final de curso da facu. Vale a pena ter este trabalho? Isso é realmente trabalhoso?

Abraços!
Thiago Senna

louds

Hmm…

class EmpresaDao {

public void update(Empresa x) {
  PrestadorDao pd = new PrestadorDao();
  for(Prestador p  : this.prestadores) {
    if(p.isUnsaved())
     pd.save(p);
    else if(p.isModified())
     pd.update(p);
   }
}

}

As partes dificeis são ordenação de operações, evitar que uma operação seja feita múltiplas vezes e ter um crítério para isUnsaved (bico, pk == null) e isModified (mais dificil, aop pode te ajudar).

Z

É o tipo de problema que faz agente se convencer cada vez mais do quanto o Hibernate é útil. :lol:

Já desse uma olhada como ele faz esse tipo de coisa (associações bi-direcionais), Thiago?

Thiago_Senna

ZehOliveira:
É o tipo de problema que faz agente se convencer cada vez mais do quanto o Hibernate é útil. :lol:

Já desse uma olhada como ele faz esse tipo de coisa (associações bi-direcionais), Thiago?

:cry: … eu queria usar Hibernate… mas seu eu fazer isso é capaz de reprovarem meu trabalho.

É capaz dos professores alegarem que eu não execitei SQL como deveria!

Thiago_Senna

Valeu Louds!

Acho que vai valer a pena implementar este recurso.

O único problema agora seria como ele descobriria que servico foi excluido, mas tudo bém. Vcs já ajudaram bastante. Acho que daqui em diante posso me virar!!! :smiley:

Abraços!
Thiago

louds

Use uma coleção inteligente.

class SmartSet extends HashSet {
 private Set removidas = new HashSet();
 private Set novas = new HashSet();
 

 public boolean add(Object o) {
   boolean b = super.add(o);
   if(b) novas.add(o); 
   return b;
 }

 public boolean remove(Object o) {
   boolean b = super.remove(o);
   if(b) removidas.add(o); 
   return b;
 }
}

Quer mais uma dica? Leeeeeia os fontes do hibernate. E se tiver de má vontade, uuuuuuse os fontes do hibernate (as modificações vão precisar ser LGPL).

Thiago_Senna

Louds:
Quer mais uma dica? Leeeeeia os fontes do hibernate. E se tiver de má vontade, uuuuuuse os fontes do hibernate (as modificações vão precisar ser LGPL).

Deixa comigo! :smiley: Vou implementar este Set inteligente… show de bola!

Abraços!
Thiago

Thiago_Senna

Pessoal...

Vejam o que acham.. decidi implementar um SmartArrayList sugerido pelo Louds, no entanto, ele guarda pra mim quais objetos foram adicionados, alterados e excluidos. Assim vai me ajudar com a implementação dos casdades!

/*
 * Created on 12/07/2005
 *
 * sabes
 */
package br.umc.sabes.util.collection;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @author thiago
 *
 * Lista que armazena internamente objetos excluídos
 */
public class SmartArrayList extends ArrayList {
	
	/**
	 * Armazena objetos adicionados
	 * 
	 */
	private List objetosAdicionados = new ArrayList();
	
	/**
	 * Armazena objetos alterados
	 * 
	 */
	private List objetosAlterados = new ArrayList();
	
	/**
	 * Armazena objetos excluidos
	 * 
	 */
	private List objetosExcluidos = new ArrayList();	
	
	/**
	 * Adiciona objeto na lista
	 * 
	 */
	public boolean add(Object o) {
		boolean b = super.add(o);
		if (b) objetosAdicionados.add(o);
		return b;
	}
	
	/**
	 * Marca um objeto para update
	 * 
	 */
	public boolean update(Object o) {
		boolean b = super.contains(o);
		if (b) objetosAlterados.add(o);
		return b;
	}
	
	/**
	 * Remove objeto da lista
	 * 
	 */
	public boolean remove(Object o) {
		boolean b = super.remove(o);
		if (b) objetosExcluidos.add(o);
		return b;
	}
	
	

	/**
	 * @return Returns the objetosExcluidos.
	 * 
	 */
	public List getObjetosExcluidos() {
		return Collections.unmodifiableList(objetosExcluidos);
	}	
	
	/**
	 * @return Returns the objetosAdicionados.
	 * 
	 */
	public List getObjetosAdicionados() {
		return Collections.unmodifiableList(objetosAdicionados);
	}
	
	/**
	 * @return Returns the objetosAlterados.
	 * 
	 */
	public List getObjetosAlterados() {
		return Collections.unmodifiableList(objetosAlterados);
	}
}

Um defeito que há nesta abordagem é que vc sempre deverá marcar quais objetos serão alterados pelo DAO, usando o comando smartArrayList.update(seuObjeto);

Vejam aqui um teste unitário com a persistência usando o cascade com esta abordagem..

/**
	 * Teste do relacionamento Empresa - ServicoPrestado
     * Teste update de Serviços Prestados
     * 
	 * @throws DAOException
	 */
	public void testUpdateServicoPrestadoAPartirDaEmpresa() throws DAOException {
		Empresa empresa = new Empresa(new Cnpj("1"), "Empresa");
		dao.create(empresa);
		
		empresa.addServicoPrestado(new ServicoPrestado("Titulo1", "Descricao1"));
		empresa.addServicoPrestado(new ServicoPrestado("Titulo2", "Descricao2"));
		dao.update(empresa);
		
		List servicos = empresa.getServicoPrestado();		
		ServicoPrestado sp1 = (ServicoPrestado) servicos.get(1);
		sp1.setTitulo("Titulo 3");
		sp1.setDescricao("Descricao 3");
		empresa.updateServicoPrestado(sp1); // marcando um objeto para update
		dao.update(empresa);
		
		long spIdPK = sp1.getIdPK();
		sp1 = null;
		
		sp1 = new ServicoPrestadoDAO().load(spIdPK);		
		assertEquals("Titulo 3", sp1.getTitulo());
		assertEquals("Descricao 3", sp1.getDescricao());		
	}

Bom, quando dou o comando empresa.updateServicoPrestado(sp1);, o objeto sp1 vai para dentro dos objetosAlterados do meu smartArrayList.

Assim, quando eu chamar o dao.update(empresa), o dao saberá quais objetos alterar!

Para o dao perceber qual objeto é novo, basta fazer o smartArrayList.getObjetosAdicionados, e ai eu uso o teste idPK == null, e se for verdadeiro, mando criar.

O que vocês acharam?
Está bom, posso ter problemas com esta solução mais pra frente? Vale a pena tocar esta idéia em frente?

Abraços!
Thiago Senna

Thiago_Senna

Aproveitando, vou aproveitar este topico para documentar um artigozinho sobre o desgin pattern

Persistent Data Collections.

Achei que tem a ver com este tópico, e pode ser úttil para uma futura consulta.

Abraços!
Thiago

Criado 12 de julho de 2005
Ultima resposta 14 de jul. de 2005
Respostas 10
Participantes 3