java休眠实体:允许通过id和对象本身设置相关对象

2022-09-04 01:49:09

我有一个以下Java类,它也是一个Hibernate实体:

@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;
    }

类别表示类别树中的节点。我正在实现一个允许CRUD类别的Web服务。例如,该接口能够创建类别树节点,并将类别 ID 作为参数传递。

我只想创建一个新的Category对象并将其保存到数据库中,而不获取父对象。我的数据提供程序类如下所示:

public void createCategory(int parent_id, String name, CategoryType type) {
    Category category = new Category();
    category.setName(name);
    // category.setParent(?); <- I don't have this object here
    // category.setParentId(id); <- but I do have the id
    category.setType(type);
    this.categoryDao.save(category);
}

我的问题是:如果假设我不会调用休眠来为我获取父对象(这将是愚蠢的),我该怎么做才能创建一个新的Category对象,并设置parent_id设置?我可以为类别类提供 setParentId/getParentId 方法吗?它会有什么休眠注释?


答案 1

Hibernate 为此方案提供了一个名为(非常令人困惑)的方法。Session.load()

Session.load()返回具有给定标识符的惰性代理而不查询数据库(如果具有给定标识符的对象已加载到当前 ,则返回对象本身)。Session

您可以使用该代理初始化要保存的实体中的关系:

category.setParent(session.load(Category.class, parent_id));

请注意,此代码不会使用给定的 id 检查 是否存在。但是,如果数据库架构中有外键约束,则在传入无效 id 时将收到约束冲突错误。Category

此方法等效的 JPA 称为 。EntityManager.getReference()


答案 2

问题还有一个解决方案 - 使用要引用的实体的默认构造函数并设置id和版本(如果它是版本控制的)。

        Constructor<S> c = entityClass.getDeclaredConstructor();
        c.setAccessible(true);

        S instance = c.newInstance();
        Fields.set(instance, "id", entityId.getId());
        Fields.set(instance, "version", entityId.getVersion());
        return instance;

我们可以使用这种方法,因为我们不使用延迟加载,而是具有GUI上使用的实体的“视图”。这使我们能够摆脱Hibernate用来填充所有渴望的关系的所有连接。视图始终具有实体的 id 和版本。因此,我们可以通过创建一个对象来填充引用,该对象在Hibernate看来不是瞬态的。

我尝试了这种方法和spect.load()的方法。他们都工作正常。我看到了我的方法中的一些优势,因为Hibernate不会在代码中的其他地方泄露其代理。如果未正确使用,我将只获取 NPE 而不是“无会话绑定到线程”异常。


推荐