I've got a following architectural problem (the text is long, but the problem should be easy for experienced java developers):
I'm learning Java and I'm developing a simple database application that uses Hibernate. I was suggested to use BO and DAO patterns for accessing database. In short, DAO is the HQL/ORM layer (create, get, update, delete, etc.) and business object performs more abstract logic stuff (retrieve all records by some criterias, get sums, etc).
I want to create or move a node in a tree via BO/DAO. Each node has it's parent and it's mapped with hibernate as follows:
@Entity
@Table(name = "category")
public class Category {
@ManyToOne
@JoinColumn(name="parent_id")
private Category parent;
public Category getParent() {
return parent;
}
public void setParent(Category parent) {
this.parent = parent;
}
Now, I want the BO to be able to create
or move
Category objects, those methods take an id
parameter:
public abstract void createCategory(int parent_id, String name, CategoryType type);
public abstract void moveCategory(int category_id, int new_parent_id);
When implementing above BO methods, I'm trying to use hibernate's session.load
to lazy load the foreign key relation:
session.load(Category.class, parent_id)
inside:
public void createCategory(int parent_id, String name, CategoryType type) {
Category category = new Category();
category.setName(name);
category.setParent(session.load(Category.class, parent_id));
category.setType(type);
this.categoryDao.save(category);
}
The DAO should keep the hibernate session (to be precise, a DAO-hibernate implementation of an abstract DAO interface), but no other class should know that anything like a hibernate session exists. Especially, BO should not have any reference to the hibernate session. And the above code does not compile ( session
is unknown).
My question is - what mistake did I make and how should it be designed to be both useful/elastic/elegant? Should I provide a Category::setParentId()
method to temporarily store parent node id and - when executing DAO's create/update - check if it was set and process accordingly? Or maybe there is any better solution?
You should mark your method as @Transactional
(add transaction support in xml settings). Then create 2 methods in dao: getCategory
and saveCategory
(you have already - save
) and operate with dao methods but not with hibernate session in business layer.
@Transactional
public void createCategory(int parent_id, String name, CategoryType type) {
...
}
Below pattern should help you: Lets take an example, if there is a business feature which operates on a table Foo.
A Generic DAO
@Repository
public abstract class DAO<T>
{
@Autowired
SessionFactory factory;
/**
* Some sample generic methods
*/
public Session getCurrentSession()
{
return factory.getCurrentSession();
}
public void create(T record) {
getCurrentSession().save(record);
}
public void update(T record) {
getCurrentSession().update(record);
}
public void delete(T record) {
getCurrentSession().delete(record);
}
public T get(Class<T> clazz, Integer id) {
return (T) getCurrentSession().get(clazz, id);
}
/**
* Rest of the generic dao methods follow
*/
}
A Generic BO
@Transactional
public abstract class BO<T>
{
public abstract DAO<T> getDAO();
/**
* Some sample generic methods
*/
public abstract void create(T record);
public abstract void update(T record);
public abstract void delete(T record);
public abstract T get(Class<T> clazz, Integer id);
/**
* Rest of the generic business methods follow
*/
}
A Specific DAO
@Transactional
@Repository
public FooDAO extends DAO<Foo>
{
}
A Specific BO
@Transactional
public FooBO extends BO<Foo>
{
@AutoWired
FooDAO dao;
@Override
public DAO<Foo> getDAO()
{
return dao;
}
@Override
public void create(T record){
dao.create(record);
}
@Override
public void update(T record) {
dao.update(record);
}
@Override
public void delete(T record) {
dao.delete(record);
}
@Override
public T get(Class<T> clazz, Integer id) {
return dao.get(Foo.class, id);
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.