我正在尝试使用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)
那么,该方法出了什么问题?如何使其发挥作用?
答案 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(主席),它将带来一个带有空变化集合的主席,我希望这是您所期待的。