1

我有以下用例:

  • 父项包含子项和 ParentTags。
  • 子项包含 ChildrenTags 及其父节点。
  • ParentTags 和 ChildrenTags 都是 T 为 Parent 或 Child 的标签。

现在我想在 Parent 中创建一个派生字段,将所有标签映射到这个父级或它的一个子级。SQL 查询很简单,但我无法通过注释给定属性来使其工作。请注意,@ManyToOne 映射的作用就像一个魅力,以便找到标签的父所有者,请参阅下面的代码(这是 @OneToMany 关系,标签可能不是我能找到的最佳名称)。

父类

@Entity
@Audited
public class Parent {

    @Id
    private Long id;

    @OneToMany(mappedBy = "parent")
    private List<Child> children;

    @OneToMany(mappedBy = "parent")
    private List<ParentTag> tags;

    // Does not work!
    @OneToMany(mappedBy = "owner")
    private List<Tag<?>> allTags;

}

子类

@Entity
@Audited
public class Child {

    @Id
    private Long id;

    @ManyToOne
    private Parent parent;

    @OneToMany(mappedBy = "child")
    private List<ChildTag> tags;

}

标记类

@Entity
@Audited
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class Tag<T> {

    @Id
    private Long id;

    protected String value;

    @NotAudited // otherwise ClassCastException
    @ManyToOne
    @JoinColumnsOrFormulas({
        @JoinColumnOrFormula(formula = @JoinFormula(
                value = "CASE WHEN parent_id IS NOT NULL THEN parent_id WHEN child_id IS NOT NULL THEN (SELECT child.parent_id FROM Child child WHERE child.id = child_id) end",
                referencedColumnName="id"))
    })
    private Parent owner;

    public abstract T getNode();

}

ChildTag.class

@Audited
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class ChildTag extends Tag<Child> {

    @ManyToOne
    private Child child;

    @Override
    public Child getNode() {
        return child;
    }

}

ParentTag.class

@Audited
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class ParentTag extends Tag<Parent> {

    @ManyToOne
    private Parent parent;

    @Override
    public Parent getNode() {
        return parent;
    }

}

我想找到一种通过给定查询或公式加载 allTags 的方法。逆映射@ManyToOne 有效(只要所有者未经过审计,就很难找到该错误)。

我已经尝试了以下解决方案但没有成功:

@JoinFormula

    @JoinColumnsOrFormulas({
        @JoinColumnOrFormula(formula = @JoinFormula(
                value = "CASE WHEN parent_id IS NOT NULL THEN parent_id WHEN child_id IS NOT NULL THEN (SELECT child.parent_id FROM Child child WHERE child.id = child_id) end",
                referencedColumnName="id"))
    })
    private List<Tag<?>> allTags;

我收到 ClassCastException,无法将公式转换为列

@加载器

@Entity
@Audited
@NamedNativeQuery(name = "loadAllTags",
    query = "SELECT * FROM Tag tag WHERE "
        + "(tag.parent_id IS NOT NULL AND tag.parent_id = :id) OR "
        + "(tag.child_id IS NOT NULL AND EXISTS (SELECT 1 FROM Child child WHERE child.id = tag.child_id AND child.parent_id = :id))")
public class Parent {    
    ...
    @Loader(namedQuery = "loadAllTags")
    private List<Tag<?>> allTags;
}

也不例外,实际上在调试时我可以看到加载器找到了所有合适的标签,但没有用它们初始化集合。我还尝试将查询放在 hbm 配置文件中,因为我知道 @Loader 和 @NamedNativeQuery 相处得不好,但没有成功(也许我在这里做错了什么)。但是我宁愿实现一个没有配置文件的解决方案。

我可以添加另一列(owner_id),但如果我能找到一种方法来解决这个问题而不改变模型,那就更好了。

我不知道泛型是否与它有关。此外,我的实体经过审计和索引。

任何帮助将不胜感激!

4

0 回答 0