简体   繁体   中英

java hibernate BO passing foreign key as DAO parameter (architecture design)

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM