@OneToMany使用@JoinFormula使用多态和泛型

时间:2015-01-22 22:39:52

标签: java hibernate jpa hibernate-onetomany

我有以下用例:

  • 父母包含儿童和父母标记。
  • 儿童包含ChildrenTags及其父节点。
  • ParentTags和ChildrenTags都是T为Parent或Child的标签。

现在我希望Parent中的派生字段映射相对于此父项或其子项之一的所有标记。 SQL查询很简单,但我不能通过注释给定的属性来使其工作。 请注意@ManyToOne映射的工作方式类似于魅力,以便找到标记的父所有者,请参阅下面的代码(这是@OneToMany关系,Tag可能不是我能为此示例找到的最佳名称)。

Parent.class

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

}

Child.class

@Entity
@Audited
public class Child {

    @Id
    private Long id;

    @ManyToOne
    private Parent parent;

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

}

Tag.class

@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有效(只要未审核所有者,就很难找到该bug)。

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

@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,Formula不能转换为列

@Loader

@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),但如果我能找到解决问题的方法而不更改模型,那就更好了。

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

任何帮助将不胜感激!

0 个答案:

没有答案