JPA / JPQL:查找单向树的根元素

发布于 2024-12-21 01:24:22 字数 2428 浏览 1 评论 0原文

JPA / JPQL:查找单向树的根元素。

我需要一些帮助来为以下问题编写命名查询。

我有以下(简化的)实体(TNode)定义,并且可以通过 JPA 保存/读取它。 该实体是单向的,因此孩子不知道父母!

现在我尝试编写一个命名查询来获取所有根元素。

我使用 JPA 2.0 (Hibernate) 并在互联网上发现了一些提示,支持单向链接。

还附加了一个简单的 JUnit (4),用于创建两棵树并将其保存到数据库中。我删除了所有断言。

如果我运行 Junit,该表将按预期显示:

ID  NAME    CHILDS_ID
1   A1  (null)
2   A11 1
3   B1  (null)
4   B11 3

我添加了 @JoinColumn 以在同一个表中包含自引用。以及简单的 SQL 问题 很容易(WHERE childs_id = null)。但是我必须如何在 JPQL 中编写这个呢?

感谢您的回答。

Uwe

@Entity
@Table(name = "TNode")
@NamedQueries({ @NamedQuery(name = "getRootNodes", query = "FROM TNode tnode ......."), })
public class TNode implements JPAObject {
    @Id
    @GeneratedValue
    private Integer id;

    private String name;

    @OneToMany(cascade = { CascadeType.REFRESH, CascadeType.MERGE, CascadeType.REMOVE })
    @JoinColumn
    private Set<TNode> childs = new HashSet<TNode>();

    // JPA only
    private TNode() {
    }

    public TNode(String name) {
    this.name = name;
    }

    public void add(TNode tNode) {
    childs.add(tNode);
    }

    @Override
    public Integer getId() {
    return id;
    }

    @Override
    public String getName() {
    return name;
    }
}

这里是简化的 Junit

@RunWith(Arquillian.class)
public class TNodeTest {
    @Deployment
    public static Archive<?> createTestArchive() {
    //@formatter:off
    Archive<?> archive = ShrinkWrap.create(WebArchive.class, "test.war")
        .addPackages(true, DummyInterfaceForTest.class.getPackage())
        .addAsLibraries(FindMavenArtifact.find("com.thoughtworks.xstream:xstream:1.4.2"))
        .addAsLibraries(FindMavenArtifact.find("xmlpull:xmlpull:1.1.3.1"))
        .addAsResource("META-INF/persistence.xml", "META-INF/persistence.xml")
        .addAsResource("import.sql", "import.sql")
        .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
    //@formatter:on
    System.out.println(archive.toString(true));
    return archive;
    }

    @Inject
    @DAO.DAOType(type = DAO.MODE.STATELESS)
    private DAO<JPAObject> dao;

    @Test
    public void testMutipleRoots() throws Exception {
    TNode root;

    root = new TNode("A1");
    root.add(new TNode("A11"));

    dao.saveOrUpdate(root);

    root = new TNode("B1");
    root.add(new TNode("B11"));

    dao.saveOrUpdate(root);
    }
}

JPA / JPQL: find root elements of a unidirectional tree.

I need some help to write a named query for the following problem.

I have the following (simplified) definition of an entity (TNode) and can save/read it via JPA.
The entity is unidirectional, so childs don't know the parent!

Now I try to write a named query to get all root elements.

I use JPA 2.0 (Hibernate) and found some hints in the internet, that unidirectional links are supported.

A simple JUnit (4) is also attached, to create two trees and save it into the db. I removed all the asserts.

If I run the Junit, the table looks as expected:

ID  NAME    CHILDS_ID
1   A1  (null)
2   A11 1
3   B1  (null)
4   B11 3

I added @JoinColumn to have the self reference in the same table. And the with simple SQL the problem
would be easy (WHERE childs_id = null). But how must I write this in JPQL?

Thanks for the answers.

Uwe

@Entity
@Table(name = "TNode")
@NamedQueries({ @NamedQuery(name = "getRootNodes", query = "FROM TNode tnode ......."), })
public class TNode implements JPAObject {
    @Id
    @GeneratedValue
    private Integer id;

    private String name;

    @OneToMany(cascade = { CascadeType.REFRESH, CascadeType.MERGE, CascadeType.REMOVE })
    @JoinColumn
    private Set<TNode> childs = new HashSet<TNode>();

    // JPA only
    private TNode() {
    }

    public TNode(String name) {
    this.name = name;
    }

    public void add(TNode tNode) {
    childs.add(tNode);
    }

    @Override
    public Integer getId() {
    return id;
    }

    @Override
    public String getName() {
    return name;
    }
}

Here the simplified Junit

@RunWith(Arquillian.class)
public class TNodeTest {
    @Deployment
    public static Archive<?> createTestArchive() {
    //@formatter:off
    Archive<?> archive = ShrinkWrap.create(WebArchive.class, "test.war")
        .addPackages(true, DummyInterfaceForTest.class.getPackage())
        .addAsLibraries(FindMavenArtifact.find("com.thoughtworks.xstream:xstream:1.4.2"))
        .addAsLibraries(FindMavenArtifact.find("xmlpull:xmlpull:1.1.3.1"))
        .addAsResource("META-INF/persistence.xml", "META-INF/persistence.xml")
        .addAsResource("import.sql", "import.sql")
        .addAsWebInfResource(EmptyAsset.INSTANCE, "beans.xml");
    //@formatter:on
    System.out.println(archive.toString(true));
    return archive;
    }

    @Inject
    @DAO.DAOType(type = DAO.MODE.STATELESS)
    private DAO<JPAObject> dao;

    @Test
    public void testMutipleRoots() throws Exception {
    TNode root;

    root = new TNode("A1");
    root.add(new TNode("A11"));

    dao.saveOrUpdate(root);

    root = new TNode("B1");
    root.add(new TNode("B11"));

    dao.saveOrUpdate(root);
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

谜兔 2024-12-28 01:24:22

在阅读了一些有关 JPQL 的内容后,我自己找到了一个解决方案。

(子)查询解决了这个问题:

query = "SELECT node FROM TNode node WHERE node.id NOT IN (SELECT DISTINCT child.id FROM TNode node, IN(node.childs) child)"), })

I found a solution by myself after reading a little bit about JPQL.

The (Sub-) Query solves the problem:

query = "SELECT node FROM TNode node WHERE node.id NOT IN (SELECT DISTINCT child.id FROM TNode node, IN(node.childs) child)"), })
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文