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

我的问题是与ManyToOne关系是可选的-即它可以为null。

这是两个表(第一个是types,第二个是metaTypes):

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

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


因此,现在存在一个问题,那就是它们如何全部归为一体。在类型表中,存在各种类型,例如可以存在的事物列表。

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

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

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

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

这是我尝试过的方法(缩短了,使用getter和setter的方法大多被省略了):

@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,但变体列表应为null。

假设我查询了“表格”类型。在这种情况下,没有MetaType,并且由于有了@NotFound注释,它默默地失败了,并且metaType字段中为null。到目前为止,一切都很好。但是由于“表”的typeID2,所以我希望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)


那么,这种方法出了什么问题?如何使它起作用?

最佳答案

好的,以下是我的操作方式,它似乎运行良好:

类型实体

@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。这是单向关系。

元类型实体

@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(椅子),它将带来一个带有空变化集合的椅子,我希望这是您所期望的。

10-06 07:01