Java 菜单树与冬眠在发挥!
我的第一个项目是Hibernate/JPA和Play!,我有一个菜单,一旦工作,将支持更改(即,轻松地将节点添加到树中)。挣扎(在>5小时的意义上)只是为了把基本的建模结合在一起: 模型:Java 菜单树与冬眠在发挥!,java,hibernate,jpa,tree,playframework,Java,Hibernate,Jpa,Tree,Playframework,我的第一个项目是Hibernate/JPA和Play!,我有一个菜单,一旦工作,将支持更改(即,轻松地将节点添加到树中)。挣扎(在>5小时的意义上)只是为了把基本的建模结合在一起: 模型: @Entity @Table(name = "Node") public class Node extends Model { @Column(nullable=false) public String description; @OneToMany(cascade=Cascade
@Entity
@Table(name = "Node")
public class Node extends Model {
@Column(nullable=false)
public String description;
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
@JoinColumn(name="parent")
public List<Node> children = new LinkedList<Node>();
@ManyToOne
@JoinColumn(name="parent", insertable=false, updatable=false)
public Node parent;
public Node(){}
}
测试:
public class MenuTest extends UnitTest {
private static final String TEST_MENU = "testMenu";
@Test
public void testMenu() {
// test build/get
Node root = NodeUtil.getRoot(TEST_MENU);
assertNotNull(root);
// delete all children - maybe from previous tests etc.
for(Node o : root.children)
o.delete();
root.save();
// test add
root = NodeUtil.getRoot(TEST_MENU);
NodeUtil.addChild(root, "child 1");
NodeUtil.addChild(root, "child 2");
NodeUtil.addChild(root, "child 3");
assertEquals(3, root.children.size());
assertEquals("child 3", root.children.get(2).description);
assertEquals(0, root.children.get(1).children.size());
Node node = root.children.get(1);
NodeUtil.addChild(node, "subchild 1");
NodeUtil.addChild(node, "subchild 2");
NodeUtil.addChild(node, "subchild 3");
NodeUtil.addChild(node, "subchild 4");
NodeUtil.addChild(root.children.get(2), "sub subchild");
assertEquals("sub subchild", root
.children.get(1)
.children.get(2)
.children.get(0)
.description);
assertEquals(4, root.children.get(1).children.size());
root.save();
// test delete
root = NodeUtil.getRoot(TEST_MENU); // regrab the root via hibernate, assuming there isnt it isnt cached this will get changes that have been persisted to the db (maybe?)
root.children.get(1).children.get(2).delete();
assertEquals(3, root.children.get(1).children.size());
//root.delete();
}
}
问题:
我不熟悉Play框架,但我可以提出一些关于使用Hibernate的观点:
- 维护内存中对象的一致状态是您的责任。考虑下面的代码:
您指示Hibernate从数据库中删除子对象,但内存中的for(Node o : root.children) o.delete(); root.save();
根对象仍然引用它们。由于关系配置为级联,Hibernate将再次尝试保存它们(我猜这是“分离实体传递到持久化”错误的原因)。所以,通过清除
来保持对象在内存中的状态一致root.children
- Hibernate在很大程度上依赖于。我不确定Play是如何管理它的,但看起来您应该在unittests中调用
,以确保现有会话状态不会影响进一步的操作:clearJPASession()
root.save(); clearJPASession(); // test delete root = NodeUtil.getRoot(TEST_MENU);
- 支持但不推荐您定义关系的方式(请参阅)。请改用以下方法:
@OneToMany(mappedBy = "parent", cascade=CascadeType.ALL, fetch=FetchType.EAGER) public List<Node> children = new LinkedList<Node>(); @ManyToOne @JoinColumn(name="parent") public Node parent;
@OneToMany(mappedBy=“parent”,cascade=CascadeType.ALL,fetch=FetchType.EAGER) public List children=new LinkedList(); @许多酮 @JoinColumn(name=“parent”) 公共节点父节点;
- 静态方法不会干扰Hibernate
delete()
,save()
调用EntityManager.flush()
,这听起来像您所说的clearJPSSession()
。(3) 我已经改变了我的关系,尝试让它工作,现在只是单向的(默认设置,正如我在你发送的链接上看到的,这是推荐的joinTable方法)。但是仍然不起作用。(4)静态和非静态都是这样吗?也就是说,非静态成员函数会干扰,或者我可以在模型对象中自由使用它们吗?@davin:非静态方法也不会干扰Hibernate,除非它们被命名为getter或setter。另外,flush()
可能还不够,因为它不会清除会话缓存,因此进一步尝试加载对象将导致相同的实例。再次感谢。我接受了你的回答,因为它帮助我解决了很多问题。
@OneToMany(mappedBy = "parent", cascade=CascadeType.ALL, fetch=FetchType.EAGER)
public List<Node> children = new LinkedList<Node>();
@ManyToOne
@JoinColumn(name="parent")
public Node parent;