这是Java中自定义对象关系映射的好方法吗?

时间:2010-12-12 18:02:04

标签: java object-relational-model

我正在开发一个使用Oracle内置“HR”数据库架构的示例Java应用程序。我想将表行视为Java对象。 HR模式中的一个表EMPLOYEES是自引用的。它有一个MANAGER_ID列,它包含(如果不是NULL)EMPLOYEES表中另一行的外键。

在面向对象的术语中,问题是如何访问给定的Employee对象的管理器(这是另一个Employee对象)。急切加载似乎不是一个好的解决方案,因为给定的Employee对象的经理也可以有一个经理,依此类推。在这种情况下急切加载的对象数量是无限的。

到目前为止我决定做的是在实例化Employee对象时急切地加载MANAGER_ID字段。然后,当请求Employee的经理Employee对象时(通过getManager()方法),后者将被延迟加载。在代码中:

public class Employee
{
    private int id;
    private int managerId;
    private Employee manager;

    public int getId()
    {
        return id;
    }

    public Employee getManager()
    {
        if(manager == null && managerId > 0)
        {
            // Lazy loading!
        }

        return manager;
    }

    public void setManager(Employee manager)
    {
        this.manager = manager;
        this.managerId = manager.getId();
    }
}

这是一个好方法吗?我唯一的问题是如何实现延迟加载。似乎Employee对象需要对其实例化器的引用 - 可能与实例化其管理器Employee对象的内容相同。

另外,我知道我可以使用其中的一个ORM框架而不是自己编写,但我自己这样做是为了更深入地了解底层流程。

编辑:为了澄清,我的这项工作的架构(例如它)根本不涉及Java EE。它是一个Java SE架构,客户端通过直接的RMI与服务器连接。

此外,上面的Employee类显然需要引用DAO来执行延迟加载。但是,我不认为这必然是紧密耦合的,因为:

  1. Employee对象可以保存对DAO实现的抽象接口的引用;和/或
  2. Employee对象可以保存对服务器对象的引用,而服务器对象又拥有对DAO的(私有)引用。
  3. 请注意,在#2的情况下,Employee对象引用的服务器对象可能与客户端引用的服务器对象相同。

1 个答案:

答案 0 :(得分:1)

如果您了解其他ORM,为什么不研究它们是如何做到的?特别是,您可能会发现Hibernate的延迟加载代理很有趣:

Hibernate将创建(在运行时,使用字节码生成)Employee的子类,它封装对尚未加载的员工对象的引用。在此类上调用任何方法(getId()除外)都会加载引用的employee对象,然后委托给它。

与您的方法相比,这样做的优点是不需要为每个关联编码延迟加载支持,但可以为所有关联编码一次,从而避免使用数据库访问代码污染域模型(托管业务逻辑)。此外,只要访问者不访问其状态,调用者就可以在不加载对象的情况下使用它。例如,他们可以这样做:

void switchJobs(Employee e1, Employee e2) {
    Employee m1 = e1.getManager();  // doesn't load the manager!
    e1.setManager(e2.getManager()); // doesn't load the manager!
    e2.setManager(m1);
}

此外,Hibernate不会在事务中多次加载相同的管理器,而是重用已经加载的持久对象或延迟加载代理。这既提高了对象模型的性能和一致性,也就是说,如果多个员工共享一个经理,一个员工修改它,另一个员工将看到该更改,并且可以使用==来比较经理。