Pra quê um monte de DAOs cheios de métodos?

Bom, eu tenho um pé atrás com AR, mas tudo bem :stuck_out_tongue:

De qualquer modo, onde você faz consultas?

Um repositório é um lugar onde você armazena entidades. Quando você rpecisa armazenar um objeto e não tem um lugar lógico no seu domínio para isso, você usaria um repositório.

É quase um DAO, mas utilizado direamente no seu domínio, está na mesma camada. Ele age como um agregado de objetos de um mesmo tipo, pro domínio não existe persistência, é como se fosse uma Collection especializada.

Se um Repositorio de Usuarios receber uma consulta:

public List listBySpec(Specification s)

Você poderia colcoar seus critérios dentro da implementação de Specification e ter apenas um método para qualquer consulta. Por aí que estou pensando…

[quote=pcalcado]Bom, eu tenho um pé atrás com AR, mas tudo bem :stuck_out_tongue:
[/quote]

Sempre é bom ter um pé atras, mas tb nao é por isso que nao vou experimentar. Até agora nao tive problemas e to até gostando, mas um dos pé continua atras. :stuck_out_tongue:

[quote=pcalcado]
De qualquer modo, onde você faz consultas?[/quote]

No meu objeto de negocio ué. :smiley:

public class User() { ... public List<User> getUserByAge(int age) { } ...

E o SQL ou melhor HQL normalmente tenho usado named query.

Agora se eu preciso algo mais trabalhado ou consultas mais complicadas eu gosto de usar um ValueListHandle.

]['s

Eu não consigo entender isso. A mistura de responsabilidades entre negócio e consulta tem que estar nesse objeto?

O que você faz assim é pegar uma série de responsabilidades e agrupar numa classe que já tem as suas próprias responsabilidades.

A classe em si fica com coesão baxíssima, se acopla à tecnologia de persistência e não é tão diferente de ter uma classe que faça o mapeamento em separado, é a mesma coisa em um lugar diferente (e impróprio IMHO).

Qual a real vantagem de fazer isso? :roll:

[quote=pcalcado]Eu não consigo entender isso. A mistura de responsabilidades entre negócio e consulta tem que estar nesse objeto?

O que você faz assim é pegar uma série de responsabilidades e agrupar numa classe que já tem as suas próprias responsabilidades.

A classe em si fica com coesão baxíssima, se acopla à tecnologia de persistência e não é tão diferente de ter uma classe que faça o mapeamento em separado, é a mesma coisa em um lugar diferente (e impróprio IMHO).

Qual a real vantagem de fazer isso? :roll: [/quote]

No meu caso, que estou usando AR a parte de consulta em si nao esta no meu objeto de negocio. Uso composicao pra fazer isso. Atualmente to usandoa implementacao que o CV postou por aqui em outro topico, adaptado a arquitetura que eu ja havia montado no meu sistema. A unica coisa que meu objeto User (do exemplo) sabe é buscar a idade, mas ele nao sabe de onde vem nem como se faz pra buscar de la.

Eu nao entendi a tua frase:

Se o que tu chama de consulta é a “arte” de buscar efetivamente os dados do banco realmente nao há essa mistura visto que meu objeto de negocio nao faz a busca propriamente.

Ps.: Acho que o assunto do topico ja desvirtuo denovo. E essa parte do AR nao tem nada a ver com meu comentários dos DAO feitos anteriormente. :stuck_out_tongue:

]['s

Posso fazer soh um comentario rapidinho? Metodos como List getUsersByAge(int age) nao sao uma boa: eh bem melhor ter um List findUsers(User example) que lida com qualquer parametro necessario (usando Hibernate, isso eh bem trivial de implementar) :slight_smile:

Hm, verdade. Nao tinha pensado nisso ainda.

Agora CV oque tu acha de tudo que ta sendo falado por aqui? Ja que tu é um que gosta de AR.

Da tua opiniao ai. :mrgreen:

]['s

Olá!

Essa discussão não é muito pro meu bico, mas eu gostei de uma solução que é a seguinte: Peguei essa idéia na aplicação PetSoar, do livro Java Open Source Programming!

Tenho uma interface PersistenceManager, uma classe que implementa a PersistenceManager, e um componenete que faz uma espècie de integração entre meu objeto de negócio e o Persistence Manager… … vou postar o código, e vejam o que acham… Talvez não ajude em nada, mas é uma maneira q achei interessante de lidar com a persistência!

[code]
public interface PersistenceManager {

/**
 * Save any object of domain in the database
 * 
 * @param obj
 */
public void save(Object obj);
/**
 * Remove any objet of domain from the database
 * 
 * @param obj
 */
public void remove(Object obj);
/**
 * Retrie a objet of domain from the database by id
 * 
 * @param id
 * @return UserStorie Object
 */
public Object load(Long id);
/**
 * Retrieve all objects of a specific object domain.
 * 
 * @param c Class of the object domain
 * @return a collection of objects
 */
public List findAll(Class c);

}[/code]

[code]
public class HibernatePersistenceManager implements PersistenceManager {

Log log = LogFactory.getLog(HibernatePersistenceManager.class);

/* (non-Javadoc)
 * @see net.java.dev.xpturbine.persistence.PersistenceManager#save(java.lang.Object)
 */
public void save(Object obj) {
	try {
		Session session = HibernateUtil.getSession();
		session.saveOrUpdate(obj);
	} catch (HibernateException e) {
		log.error(e.getMessage(), e);
		throw new PersistenceException(e.getMessage(), e);
	}
}

/* (non-Javadoc)
 * @see net.java.dev.xpturbine.persistence.PersistenceManager#remove(java.lang.Object)
 */
public void remove(Object obj) {
	try {
		Session session = HibernateUtil.getSession();
		session.delete(obj);
	} catch (HibernateException e) {
		log.error(e.getMessage(), e);
		throw new PersistenceException(e.getMessage(), e);
	}

}

/* (non-Javadoc)
 * @see net.java.dev.xpturbine.persistence.PersistenceManager#load(java.lang.Long)
 */
public Object load(Long id) {
	Object obj;
	try {
		Session session = HibernateUtil.getSession();
		obj = session.load(UserStorie.class, id);
	} catch (HibernateException e) {
		log.error(e.getMessage(), e);
		throw new PersistenceException(e.getMessage(), e);
	}
	return obj;
}

/* (non-Javadoc)
 * @see net.java.dev.xpturbine.persistence.PersistenceManager#findAll(java.lang.Class)
 */
public List findAll(Class cls) {
	List list = Collections.EMPTY_LIST;
	
	try {
		Session session = HibernateUtil.getSession();
		list = session.find("FROM userStorie IN CLASS " + cls.getName());
	} catch (HibernateException e) {
		log.error(e.getMessage(), e);
		throw new PersistenceException(e.getMessage(), e);
	}
	
	return list;
}

}[/code]

[code]
public class ReleaseManager {

private PersistenceManager persistenceManager;

/**
 * Set a persistence manager.
 * 
 * @param persistenceManager The persistenceManager to set.
 */
public void setPersistenceManager(PersistenceManager persistenceManager) {
	this.persistenceManager = persistenceManager;
}

/**
 * Save a user storie in the database.
 * 
 * @param userStorie
 */
public void saveUserStorie(UserStorie userStorie) {
	persistenceManager.save(userStorie);
}
/**
 * Remove a user storie from the database
 * 
 * @param userStorie
 */
public void removeUserStorie(UserStorie userStorie) {
	persistenceManager.remove(userStorie);
}
/**
 * Retrieve a user storie by id from the database
 * 
 * @param id UserStorie ident
 * @return a retrieved UserStorie
 */
public UserStorie loadUserStorie(long id) {
	Object storie = persistenceManager.load(new Long(id));
	return (UserStorie) storie;
}
/**
 * Retrievel all user stories from the database
 * 
 * @return list of user stories
 */
public List findAllUserStories() {
	List userStories = persistenceManager.findAll(UserStorie.class);
	return userStories;
}

}[/code]

Ainda tem alguns errinhos e melhorias para ser feitas. Por enquanto o componente só persiste a classe UserStorie, mas em breve terei outras classes, e para cada uma delas irei acrescentando métodos para tratar dessas responsabilidades, mas enquanto isso, a classe HibernatePersistenceManager irá crescer pouco, e se manterá simples e fácil de entender!!!

Abraços!
Thiago Senna

Não sou puxa-saco.
Cara eu acho que vc tem bagagem até de sobra para postar nesse tópico.

É lógico que tem especialistas como o Shoes e Cv em arquitetura mas sua ppinião é bem interessante.

Não entendi, ele dá um load passando só um “Long”, mas dá um findAll passando a “classe”.

Ou ele faz de um jeito ou faz de outro, não acho que se deva misturar tudo assim não. Bota a classe sendo passada no load também ou então tira a classe do findAll.

[quote=Maurício Linhares]Não entendi, ele dá um load passando só um “Long”, mas dá um findAll passando a “classe”.

Ou ele faz de um jeito ou faz de outro, não acho que se deva misturar tudo assim não. Bota a classe sendo passada no load também ou então tira a classe do findAll.[/quote]

Olá Maurício!

Esta parte esta realmente precisando de uma melhoria. Eu vou adicionando estas melhorias de acordo vou precisando delas.

No caso do meu objeto UserStorie, sua identificação é um atributo do tipo Long!

Em breve criarei outro objeto que se chamará Release, e depois outros e mais outros, Quando um deles for algum outro tipo de identificação, dai eu uso

public Obect load(Object obj);

Em suma, essa parte realmente precisaria de uma melhoria, mas eu naum a fiz por que naum precisei ainda! :wink:

Abraços!
Thiago Senna

[quote=Thiago Senna]Em breve criarei outro objeto que se chamará Release, e depois outros e mais outros, Quando um deles for algum outro tipo de identificação, dai eu uso

public Obect load(Object obj); [/quote]

Thiago,

Tenta usar Serializable ao inves de Long ou Object. A meu ver fica melhor.

public Obect load(Serializable id);

]['s

Fábio,

essa eu não imaginava! :smiley: Deixa comigo, vou usar Serializable então!!! :wink:

Abraços!
Thiago

Query by example só tem um porêm, todos atributos da tua tua classe tem que possuir um valor inválido, normalmente null, e ser possivel ter somente alguns valores atribuidos. QBE, até onde eu ví, normalmente leva a você ter um punhado de java beans/VOs e não domain objects.

Achei essa discussão muitooooo interessante e resolvi criar uma classe genérica(com apenas ações CRUD) para os meus Dao’s e obtive resultados significativos em relação a reutilização, irei mostrar o código se algo pode ser implementado favor me avisem.

public interface IGenericPersistenceDao extends Serializable {
    
    public void insert(IBean bean) throws SystemException;
    
    public void update(IBean bean) throws SystemException;
    
    public Object selectPrimaryKey(Integer pk) throws SystemException;
    
    public Collection select(IBean bean) throws SystemException;
    
    public void delete(IBean bean) throws SystemException;
    
}

// Minha classe genérica do Hibernate
public abstract class AbstractGenericPersistenceDao implements IGenericPersistenceDao {

    private IConexao hibernateDao;
    private Session session;
    
	public AbstractGenericPersistenceDao() throws SystemException {
        hibernateDao = Conexao.getInstance();
        session = (Session) hibernateDao.getConnection();
	}
	
	private boolean isBean(IBean bean) throws SystemException {
		if(getClassBean().getClass().getName().equalsIgnoreCase(bean.getClass().getName())){
			return true;
		}
		return false;
	}
	
	private void validationBean(IBean bean) throws SystemException {
    	if(!isBean(bean)){
    		throw new SystemException("Tipo de objeto Bean é inválido");
    	}
	}
	
	public void insert(IBean bean) throws SystemException {
        try {
       	    validationBean(bean);
            session.save(bean);
            session.flush();
        } catch(HibernateException hibernateException) {
            throw new SystemException(hibernateException);
        }
	}

	public void update(IBean bean) throws SystemException {
        try {
        	validationBean(bean);
            session.update(bean);
            session.flush();
        } catch(HibernateException hibernateException) {
            throw new SystemException(hibernateException);
        }
	}

	public Object selectPrimaryKey(Integer pk) throws SystemException {
        try {
        	validationBean(getClassBean());
        	Object object = null;
        	object = session.load(getClassBean().getClass(), pk);
            session.flush();
            return object;
        } catch(HibernateException hibernateException) {
            throw new SystemException(hibernateException);
        }
	}

	public Collection select(IBean bean) throws SystemException {
		try {
			validationBean(bean);
			String sqlString = "from "+bean.getClass().getName();
			List list = session.find(sqlString);
			Collection collection = new ArrayList(list);
			return collection;
		} catch(HibernateException he) {
			throw new SystemException(he);
		}
		
	}

	public void delete(IBean bean) throws SystemException {
        try {
        	validationBean(bean);
            session.delete(bean);
            session.flush();
        } catch(HibernateException hibernateException) {
            throw new SystemException(hibernateException);
        }
	}
	
	abstract protected IBean getClassBean() throws SystemException;
	
}

Agora os meus daos ficaram simplesmente assim. :smiley:

public class PessoaDaoNew extends AbstractGenericPersistenceDao {

	public PessoaDaoNew() throws SystemException {
		super();
	}

	protected IBean getClassBean() throws SystemException {
		return AbstractBeanFactory.createBean(PessoaBean.class);
	}

}


public class PessoaFisicaDaoNew extends AbstractGenericPersistenceDao {

	public PessoaFisicaDaoNew() throws SystemException {
		super();
	}

	protected IBean getClassBean() throws SystemException {
		return AbstractBeanFactory.createBean(PessoaFisicaBean.class);
	}

}


public class PessoaJuridicaDaoNew extends AbstractGenericPersistenceDao {

	public PessoaJuridicaDaoNew() throws SystemException {
		super();
	}

	protected IBean getClassBean() throws SystemException {
		return AbstractBeanFactory.createBean(PessoaJuridicaBean.class);
		
	}

}

Até ontem( :slight_smile: ) as minhas ações CRUD’s eram codificadas(ou replicadas?) dentro de cada Dao, agora preciso apenas abstrair um método que retorna o bean do Dao para manter a integridade dos daos, tipo pra não chamar um Dao N passando um bean M…

O problema será quando tiver uma consulta específica, estou pensando ainda em como implementar… :?

Fui…

Sem mais, Rodrigo.


heehhe

Rodrigo, porque você não cria um único Dao, que faça todas as operações de CRUD, salvar, atualizar, listar e carregar pelo identificador (poderia até ter buscar por exemplos). Aí quando você precisar de uma busca específica, cria um DaoEntidade com essa busca, mas deixa os CRUD lá no CrudDao, ou seja lá o que ele for.

Essa validação que você esta fazendo é desnecessária, se o objeto não puder ser persistido pelo Hibernate, ele vai lançar uma exceção.

Eu não vi nenhuma transação sendo aberta e terminada no seu código, ele está fazendo alguma atualização no banco de dados? Ele está funcionando?

Evite usar o flush(), o Hibernate sabe quando ele deve enviar os dados pra uma tabela e só vai fazer isso quando for estritamente necessário, diminuindo o gasto com banda de rede.

Eu acho que eu ja disse o bastante aqui, ou faltou alguma coisa? :slight_smile:

[quote=Maurício Linhares]Rodrigo, porque você não cria um único Dao, que faça todas as operações de CRUD, salvar, atualizar, listar e carregar pelo identificador (poderia até ter buscar por exemplos). Aí quando você precisar de uma busca específica, cria um DaoEntidade com essa busca, mas deixa os CRUD lá no CrudDao, ou seja lá o que ele for.
[/quote]
Acho que não seria válido ter apenas um Dao q fizesse o CRUD de todas as tabelas, eu prefiro ter um Dao(desde que esse fique bem enxuto) pra cada tabela do jeito q está, por questão de arquitetura e tals.

Eu faço essa validação para ter certeza que no DaoUsuario(exemplo) estará sempre passando o BeanUsuario, assim ele nem chegará nessa exceção que o hibernate mandaria e creio que fica mais seguro a nível de programação.

Sim está fazendo o CRUD certinho, para controle de transação fiz uma classe que cria apenas uma única transação para todo(s) o(s) negócio(s), eu a chamo na ultima camada do sistema, exemplo

...
// Aqui poderia ser um Servlet, Swing...
    public static void main(String[] args) {

        ITransaction t = null;
        try {
            t = SimpleTransaction.getInstance();
            t.start();
            
	    // Aqui fica as classes de negócio e eles chamam os Dao's necessários.

	    t.commit();
        } catch(SystemException se) {
            t.rollback();
            se.printStackTrace();
        } finally {
            t.close();
    }
...

Com o código acima usa vários regras(e consequentemente vários daos) e se acontecer alguma exceção dou um rollback, estando tudo ok comito a transação ai ele salva no banco, por enquanto ainda não estou usando o JTA(fiz a classe de transação na unha mesmo).

[quote=Maurício Linhares]
Evite usar o flush(), o Hibernate sabe quando ele deve enviar os dados pra uma tabela e só vai fazer isso quando for estritamente necessário, diminuindo o gasto com banda de rede.[/quote]
Blz valew pela dica. :wink:

Ah e sobre as consultas específicas pra cada entidade já resolvi o problema, implemento no Dao uma interface com os métodos a mais. heheh

Falow!

Sem mais, Rodrigo.

Se você vai fazer um Dao Crud pra cada entidade, porque não faz a validação no próprio parâmetro?

[code]public void salvar (Usuario usuario)

public Usuario carregar (Integer id)[/code]

Fica muito mais limpo e dá um bom motivo pra se ter vários Daos fazendo CRUD do mesmo jeito. Do jeito que você está fazendo tá só duplicando código.

[quote=Maurício Linhares]Se você vai fazer um Dao Crud pra cada entidade, porque não faz a validação no próprio parâmetro?

[code]public void salvar (Usuario usuario)

public Usuario carregar (Integer id)[/code]

Fica muito mais limpo e dá um bom motivo pra se ter vários Daos fazendo CRUD do mesmo jeito. Do jeito que você está fazendo tá só duplicando código.

[/quote]
Não véio acho que vc não entedeu(ou eu não expliquei direito), criei um Dao pai(classe abstrata) onde ele provém as ações CRUD para os restantes dos Daos filhos, não estou duplicando(ou sobrepondo) os métodos nos filhos, apenas o método que retorna o bean do Dao para validar posteriormente.

Sem mais, Rodrigo.