我正在尝试使用 JavBeans + Hibernate 映射创建开源库,该库使用提供的数据库来读取值(它只读取,不写入)。遗憾的是,这个数据库设计得不是很好。
我的问题是可选的 ManyToOne 关系 - 即它可以为空。
这是两个表(第一个是types
,第二个是metaTypes
):
+--------+---------------+
| typeID | typeName |
+--------+---------------+
| 1 | Chair |
| 2 | Table |
| 3 | Picnic Table |
| 4 | Bedside Table |
+--------+---------------+
+--------+--------------+
| typeID | parentTypeID |
+--------+--------------+
| 3 | 2 |
| 4 | 2 |
+--------+--------------+
所以,现在的问题是这一切如何结合在一起。在类型表中有各种类型,就像它们可以存在的事物的列表一样。
在第二个表中,这些内容被分组在一起。正如您所看到的,“野餐 table ”在 metaTypes
表中有一个条目作为类型表的子项。
如果类型是基类型,则 metaTypes
表中没有相应的条目。在设计良好的数据库中,至少会存在一个 parentTypeID
为 NULL 的条目,但事实并非如此。我通过在 Type
bean 中使用 @NotFound(action = NotFoundAction.IGNORE)
解决了这个问题。
在真实的数据库中,metaType
表中有更多包含附加相关信息的列,因此我必须有一个 MetaType
bean。
在这个冗长的介绍之后,真正的问题出现了:
如何将类型
映射到它的变体(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不为空,但变体列表应该为空。
假设我查询“Table”类型。在这种情况下,没有 MetaType,并且由于 @NotFound
注释,它会默默地失败,并且 metaType
字段中存在 null。到目前为止,一切都很好。但由于“Table”的 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)
那么,这种方法有什么问题以及如何让它发挥作用?
最佳答案
好的,以下是我的方法,看起来效果很好:
类型实体
@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(椅子),它将带来一个带有空变体集合的椅子,我希望这正是您所期望的。
关于java - 可选的多对一与 hibernate ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25461413/