我有一个下面的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类别的CRUD服务。例如,该接口能够创建类别树节点,并将类别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);
}我的问题是:如果假设我不会调用hibernate为我获取父对象(这将是愚蠢的),我可以做什么来创建一个设置了parent_id的新类别对象?是否可以为Category类提供setParentId/getParentId方法?它会有什么hibernate注解?
发布于 2013-04-17 02:09:02
Hibernate为这个场景提供了一个叫做Session.load()的方法(非常令人困惑)。
Session.load()返回一个具有给定标识符的惰性代理,而不查询数据库(如果具有给定标识符的对象已经加载到当前Session中,则它本身返回一个对象)。
您可以使用该代理来初始化要保存的实体中的关系:
category.setParent(session.load(Category.class, parent_id));请注意,此代码不会检查是否存在具有给定id的Category。然而,如果您的DB模式中有一个外键约束,那么当传入无效的id时,您将得到一个违反约束的错误。
与此方法等效的JPA称为EntityManager.getReference()。
发布于 2014-01-14 20:38:45
还有一个解决方案-使用你想要引用的实体的默认构造函数,并设置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和版本。因此,我们可以通过创建一个看起来像是休眠的对象来填充引用。
我尝试了这种方法和使用session.load()的方法。它们都工作得很好。我在我的方法中看到了一些好处,因为Hibernate不会在代码中的其他地方泄漏它的代理。如果没有正确使用,我将只获取NPE,而不是“没有绑定到线程的会话”异常。
发布于 2013-04-17 02:11:41
您可以定义lazy init
@ManyToOne(fetch=FetchType.LAZY)我猜这个列是可以为空的,所以保存没有父目录(根目录)的Category是没有问题的
https://stackoverflow.com/questions/16043761
复制相似问题