带有hibernate的可选ManyToOne

时间:2014-08-23 11:25:50

标签: java hibernate jpa

我正在尝试使用JavBeans + Hibernate映射创建开源库,该映射使用提供的数据库来读取值(它只读取,不写入)。可悲的是,这个数据库设计得不是很好。

我的问题是可选的ManyToOne关系 - i.E.它可以为空。

以下是两个表格(第一个是types,第二个是metaTypes):

+--------+---------------+
| typeID |   typeName    |
+--------+---------------+
|      1 | Chair         |
|      2 | Table         |
|      3 | Picnic Table  |
|      4 | Bedside Table |
+--------+---------------+

+--------+--------------+
| typeID | parentTypeID |
+--------+--------------+
|      3 |            2 |
|      4 |            2 |
+--------+--------------+

所以,现在问题是这一切如何属于一起。在类型表中有各种类型,例如它们可以存在的事物列表。

在第二个表中,这些东西组合在一起。如您所见,“野餐表”在metaTypes表中有一个条目作为类型表的子项。

如果类型是基类型,则metaTypes表中没有相应的条目。在一个设计良好的数据库中,至少除了存在一个NULL为parentTypeID的条目,但它不会。我在@NotFound(action = NotFoundAction.IGNORE) bean中使用Type解决了这个问题。

在真实数据库中,metaType表中有更多列包含其他相关信息,因此我必须拥有MetaType bean。

在这篇冗长的介绍之后,出现了真正的问题:
如何将Type映射到其变体(MetaType)?

这就是我的尝试(缩短,吸气剂和制定者大多是无效的):

@Entity
@Table(name = "types")
public class Type {

    @Id
    private int typeID;     
    private String typeName, description;

    // meta types/ variations

    @OneToOne
    @JoinColumn(name = "typeID", insertable = false, updatable = false, nullable = true)
    @NotFound(action = NotFoundAction.IGNORE)
    private MetaType metaType; // -> this works as expected

    @OneToMany
    @JoinColumn(name = "typeID", referencedColumnName = "parentTypeID")
    @NotFound(action = NotFoundAction.IGNORE)
    private List<MetaType> variations; // this doesn't work

    /**
     * This method is quite easy to explain: Either this type is a base
     * type, in which case it has no metaType but holds the variations directly,
     * or it is a dervied type, in which case we get it's parent type and list the
     * variations of the parent type.
     */
    public List<MetaType> getVariations () {
        if (metaType != null) {
            return metaType.getParentType().getVariations();
        }
        return variations;
    }
}

@Entity
@Table (name = "metaTypes")
public class MetaType {

    @Id
    private int typeID;

    private Integer parentTypeID;

    // id <> object associations

    @OneToOne (mappedBy = "metaType")
    @JoinColumn(name = "typeID", insertable = false, updatable = false)
    private Type type;

    @OneToOne
    @JoinColumn(name = "parentTypeID", referencedColumnName = "typeID", insertable = false, updatable = false)
    private Type parentType;
}

目标应该是明确的。 假设我查询“床头柜”。那么metaType不是null,但变体列表应该是。

假设我查询了“表”类型。在这种情况下,没有MetaType,并且由于@NotFound注释,它默默地失败并且metaType字段中存在空值。到现在为止还挺好。但由于“表格”的typeID 2,我希望variations列表包含两个条目。但我在下面得到了例外。

但不知怎的,这不起作用,我得到以下例外:

Exception in thread "main" java.lang.NullPointerException
    at org.hibernate.cfg.annotations.CollectionBinder.bindCollectionSecondPass(CollectionBinder.java:1456)
    at org.hibernate.cfg.annotations.CollectionBinder.bindOneToManySecondPass(CollectionBinder.java:864)
    at org.hibernate.cfg.annotations.CollectionBinder.bindStarToManySecondPass(CollectionBinder.java:779)
    at org.hibernate.cfg.annotations.CollectionBinder$1.secondPass(CollectionBinder.java:728)
    at org.hibernate.cfg.CollectionSecondPass.doSecondPass(CollectionSecondPass.java:70)
    at org.hibernate.cfg.Configuration.originalSecondPassCompile(Configuration.java:1695)
    at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1424)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1844)

那么,该方法出了什么问题?如何使其发挥作用?

1 个答案:

答案 0 :(得分:1)

好的,以下是我的方式,它似乎工作正常:

类型实体

@Entity
public class Type {

    @Id
    @Column(name = "typeId")
    private Integer id;

    @Column(name="typeName")
    private String name;


    @OneToMany
    @JoinColumn(name="parentTypeId")
    List<MetaType> metaTypes;
}

请注意,我的@OneToMany未使用mappedBy属性。在这种情况下,我使用的是@JoinColumn。这是一种单向关系。

MetaType实体

@Entity
public class MetaType {

    @Id
    private Integer id;

    @MapsId
    @OneToOne
    @JoinColumn(name = "typeId")
    private Type type;

    @ManyToOne
    @JoinColumn(name = "parentTypeId")
    private Type parentType;
}

现在,我恢复了一个给定的类型,就像你给出的例子一样,我得到了正确的数据:

TypeService service = ...;
Type t = service.getTypeById(2);

System.out.println(t.getName());
for(MetaType mt : t.getMetaTypes()){
    System.out.println("\t" + mt.getType().getName() + "-> " + mt.getParentType().getName());
}

这会产生输出

Table
    Picnic Table-> Table
    Bedside Table-> Table

它也适用于没有变化的类型。如果您查询类型2(主席),它将带来一个带有空变化集合的主席,我希望这是您所期待的。