Você está na página 1de 10

Java/Hibernate: Não repita o DAO com um GenericDao

Aqui, gostaria de propor uma boa prática em relação à implementação do GenericDao porque as operações básicas para persistência de dados são
todas idênticas independentemente do objeto a salvar, os métodos em questão são os de um CRUD: registro (Create), leitura (Read ), Atualização
(Update) e exclusão (Delete).

Portanto, não repita o DAO!!!! para aumentar a produtividade do nosso código devido a um GenericDao.

DAO genérico
A seguir, as etapas para implementar um DAO genérico no sistema ORM:

Em primeiro lugar, precisamos de uma interface DAO genérica que contenha os métodos CRUD comuns disponíveis, nossas outras interfaces
DAO específicas devem estendê-la:

public interface GenericDao<T, PK extends Serializable> {

PK create(T persistentObject);

T get(PK id);

List<T> getAll();

void update(T persistentObject);

void createOrUpdate(T persistentObject);

void delete(T persistentObject);


}

Então, a implementação da interface acima é simples, mas as outras implementações DAO também a estenderão:
@Transactional(propagation=Propagation.MANDATORY)

public class GenericDaoImpl<T, PK extends Serializable> extends HibernateDaoSupport implements GenericDao<T, PK> {

private Class<T> type;

public GenericDaoImpl(SessionFactory sessionFactory, Class<T> type) {


super.setSessionFactory(sessionFactory);
this.type = type;
}

@SuppressWarnings("unchecked")

public PK create(T o) {

return (PK) getSession().save(o);


}

@SuppressWarnings("unchecked")
@Transactional(propagation=Propagation.REQUIRED, readOnly=true)

public T get(PK id) {


T value = (T) getSession().get(type, id);

if (value == null) {

return null;
}

if (value instanceof HibernateProxy) {


Hibernate.initialize(value);
value = (T) ((HibernateProxy) value).getHibernateLazyInitializer().getImplementation();
}

return value;
}

@SuppressWarnings("unchecked")
@Transactional(propagation=Propagation.REQUIRED, readOnly=true)

public List<T> getAll() {


Criteria crit = getSession().createCriteria(type);
return crit.list();
}

public void createOrUpdate(T o) {

if (o instanceof AbstractPersistentObject) {

if (((AbstractPersistentObject) o).isCreation()) {
getSession().saveOrUpdate(o);

} else {
getSession().merge(o);
}

} else {

throw new RuntimeException("this method support only AbstractPersistentObject");


}
}

public void update(T o) {


getSession().update(o);
}

public void delete(T o) {


getSession().delete(o);
}

DAO específico
Aqui, um exemplo usando a classe e interface abaixo em um DAO específico:

Exemplo de uma interface DAO específica que poderia chamar os métodos genéricos:

public interface ChapterDao extends GenericDao<Chapter, String> {

/**

* Find the chapter by number.

*/

public List<Chapter> findByNumber(String number) throws DataAccessException;


...
}

Em seguida, sua implementação que contém os métodos genéricos e o método específico ‘findByNumber’:

@Repository("chapterDao")
@Scope("singleton")

public class ChapterDaoHibernateImpl extends GenericDaoImpl<Chapter, String> implements ChapterDao {


@Autowired

public ChapterDaoHibernateImpl(@Qualifier("sessionFactory") SessionFactory sessionFactory) {


super(sessionFactory, Chapter.class);
}

/**
* Find the chapter by number.
*/
@SuppressWarnings("unchecked")
@Override
@Transactional(propagation=Propagation.MANDATORY, readOnly=true)
public List<Chapter> findByNumber(String number) throws DataAccessException {
StringBuffer hql = new StringBuffer("select chapter from Chapter chapter ");
hql.append(" where chapter.number=:number ");
Query query = getSession().createQuery(hql.toString());
//

query.setString("number", number);
List<Chapter> chapters = query.list();
return chapters;
}

...
}

Essas classes e interfaces são construídas em torno das melhores práticas definidas na seção HashCode, métodos Equals e camada ORM do post
Java/Hibernate: HashCode, métodos Equals.
Assim, nosso POJO deve estender uma classe abstrata com os métodos HashCode, Equals substituídos para comparar corretamente dois objetos e
contendo também os atributos ‘id’ e ‘version’:

/**
* AbstractPersistentObject
* @author Huseyin OZVEREN
*/

public abstract class AbstractPersistentObject {


private String id = IdGenerator.createId();

private Integer version = null;


public String getId() {

return this.id;
}

public void setId(String value) {


this.id = value;
}

public Integer getVersion() {

return this.version;
}

public void setVersion(Integer value) {


this.version = value;
}
public boolean equals(Object o) {

if (this == o) return true;

if (o == null || !(o instanceof AbstractPersistentObject )) {

return false;

AbstractPersistentObject other = (AbstractPersistentObject ) o;

// se o id estiver faltando, retorna false

if (id == null) return false;

// equivalência por id
return id.equals(other.getId());
}

public int hashCode() {

if (id != null) {

return id.hashCode();

} else {

return super.hashCode();
}
}

public String toString() {


return this.getClass().getName()+ "[id=" + id + "]";

}
public boolean isCreation() {

return version == null;


}

public void regenerateId() {


id = IdGenerator.createId();
version = null;
}

public AbstractPersistentObject() {
}

...
}

O IdGenerator gera um Id único:

public class IdGenerator {

public static String createId() {


UUID uuid = java.util.UUID.randomUUID();
return uuid.toString();
}
}

Exemplo de classes de negócio ‘Livro’ e ‘Capítulo’ na camada ORM:


public class Book extends AbstractPersistentObject {

// ------------------------- ATRIBUTOS -------------------------

private String title;

private String category = null;

private int year;

private boolean previouslyPublished = false;

private String isbn10;

private String isbn13;

private Set<Author> authors = new HashSet<Author>();

private double price = 0;

private Language language = null;


private Set<Chapter> chapters = new HashSet<Chapter>();
...

public class Chapter extends AbstractPersistentObject {

// ------------------------- ATRIBUTOS -------------------------

private Book book = null;

private Calendar creationDate = null;


private Calendar modifDate = null;

private String title = null;

private int number = 0;

private String content = null;


// ------------------------- ATRIBUTOS -------------------------
public void setBook(Book book) {
this.book = book;
}

public Book getBook() {


book = ORMUtils.initializeAndUnproxy(book);

return book;
}
...
}

O código-fonte da interface GenericDaoImpl e GenericDao estão no anexo do arquivo ZIP.

Este projeto precisa das seguintes bibliotecas: commons-beanutils-1.7.0.jar, commons-lang-2.4.jar, commons-logging-1.1.1.jar, hibernate-core-
3.3.1.GA.jar, junit-4.1.jar and spring-2.5.5.jar.

Conclusão:

Uma boa prática na programação de n camadas é agrupar as consultas na camada de serviço. O uso de um DAO genérico reduzirá o
número de linhas de código porque todos os métodos de acesso padrão estão disponíveis em uma classe. Assim, a camada de serviço
conterá apenas os métodos complexos. Além disso, todas as consultas com consultas HQL serão agrupadas em um único objeto de
serviço que corresponde a um objeto de domínio que representa um módulo.

Download: test_ORMTools.zip

Você também pode gostar