0

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?

4

2 に答える 2

0

以下のパターンが役に立ちます: テーブル Foo で動作するビジネス機能がある場合、例を見てみましょう。

ジェネリック 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
    */
}

一般的な 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
    */
}

特定のDAO

@Transactional
@Repository
public FooDAO extends DAO<Foo>
{
}

特定の 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); 
    }
}
于 2013-04-17T05:23:19.147 に答える