JPA / JPQL: найти корневые элементы однонаправленного дерева - PullRequest
0 голосов
/ 15 декабря 2011

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 проблема было бы легко (ГДЕ childs_id = null). Но как мне написать это на JPQL?

Спасибо за ответы.

Уве

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

1 Ответ

1 голос
/ 06 января 2012

Я нашел решение самостоятельно, прочитав немного о JPQL.

(Sub-) Query решает проблему:

query = "SELECT node FROM TNode node WHERE node.id NOT IN (SELECT DISTINCT child.id FROM TNode node, IN(node.childs) child)"), })
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...