我一直在努力在Java / JPA(Hibernate)中实现一个简单的ForeignKey ManyToOne协会......但没有成功。现在是时候寻求帮助了;-)
我有两个数据库表,如下所示:
请看这里:
这样的对象:
@Entity
@Table(name = "sa_s_cat")
public class SCat implements Serializable {
@Id
private int catId;
private String catSuffix;
private String catDesc;
private Lkzs lkz;
private Date cdate;
private String cuser;
...
@Entity
@Table(name = "sa_s_subcat")
public class SSubCat implements Serializable {
@Id
private int subcatId;
private int catId;
@ManyToOne
@JoinColumn(name = "catId")
private SCat cat;
private String subcatSuffix;
private String subcatDesc;
private boolean subcatShowProd;
private boolean subcatShowComp;
private boolean subcatShowQual;
private boolean subcatShowDetail;
private Lkzs lkz;
private Date cdate;
private String cuser;
...
我收到此错误消息:
...
2014-07-11 09:16:32,649 [main] DEBUG org.hibernate.engine.jdbc.internal.JdbcServicesImpl - configure() - JDBC version : 4.0
2014-07-11 09:16:32,665 [main] TRACE org.hibernate.engine.jdbc.cursor.internal.StandardRefCursorSupport - supportsRefCursors() - JDBC DatabaseMetaData class does not define supportsRefCursors method...
...
与此同时,我搜索了许多论坛,阅读了文档和教程......因此,这应该可以正常工作。
答案 0 :(得分:0)
映射对象而不是列
问题是您已经有效地将同一个DB列(catId外键)映射到实体中的两个字段。您已将其直接映射为catId的原始int,并将对象关系映射为SCat cat。
在JPA中,您必须尝试忘记数据库实现并考虑对象。 SSubCat 有一个 SCat,好的,所以在SCubCat中添加一个SCat类型的字段。现在在注释中,您会考虑如何在数据库中完成此操作。您有一个名为catId的外键列,您可以使用@JoinColumn指定。
如果您尝试同时指定基本列和对象关系,那么JPA在持久化对象时不知道选择哪个。正如您所知,纠正这种情况的一种方法是将其中一个字段指定为不可插入或可更新。 JPA将在从数据库检索时填充它们,但是当您保存回数据库时,它将仅保存仍可更新的字段的值。
像这样为一列提供两个字段的另一个问题是它们很快就会失去同步。如果你调用setCat来改变SCat对象,那么catId仍将是旧SCat的id。您必须在setter中添加手动代码才能使两个字段保持同步。你不是真的想要这个,除非你有一些奇怪的要求,这意味着你绝对必须这样做。你可能没有,只是映射对象。
双向一对多
使用JPA,更常见的是将其映射为如下所示的双向关系。
@Entity
@Table(name = "sa_s_cat")
public class SCat implements Serializable {
@Id
private int catId;
// mappedBy = the field in the other class that is the ManyToOne side
@OneToMany(mappedBy="cat")
private List<SSubCat> subCategories;
@Entity
@Table(name = "sa_s_subcat")
public class SSubCat implements Serializable {
@Id
private int subcatId;
// The join column is the foreign key column in the DB
@ManyToOne
@JoinColumn(name = "catId")
private SCat cat;
单向一对多
你说你想要一个单向的@ManyToOne。因为这只映射在关系的一侧,所以理论上你需要告诉JPA两个表中的列名(除非两个表中的列具有相同的名称 - 在你的情况下他们这样做但是我已经指定了两个这里展示如何)。假设您正在使用JPA 2.0,并且您已经检查过您的提供商是否支持此功能......那么您将需要这样的内容。
@Entity
@Table(name = "sa_s_subcat")
public class SSubCat implements Serializable {
@Id
private int subcatId;
@ManyToOne
@JoinColumn(name="catId", referencedColumnName="catId")
private SCat cat;
但是,虽然我会寻求双向关系。
答案 1 :(得分:0)
经过长时间的试验和错误后,我找到了解决方案。
我从数据库中删除了外键定义并更改了以下代码:
@Entity
@Table(name = "sa_s_cat")
public class SCat implements Serializable {
@Id
private int catId;
private String catSuffix;
private String catDesc;
private Lkzs lkz;
private Date cdate;
private String cuser;
...
@Entity
@Table(name = "sa_s_subcat")
public class SSubCat implements Serializable {
@Id
private int subcatId;
private int catId;
private String subcatSuffix;
private String subcatDesc;
private boolean subcatShowProd;
private boolean subcatShowComp;
private boolean subcatShowQual;
private boolean subcatShowDetail;
private Lkzs lkz;
private Date cdate;
private String cuser;
@ManyToOne(optional = false)
@JoinColumn(name = "catId", insertable = false, updatable = false)
private SCat cat;
...
但这引出了一些问题,我希望有人可以向我解释:
必须在数据库中定义外键以实现与hibernate / JPA的映射,或者我是否只能在代码中进行映射 - 我更喜欢哪种?
上述解决方案是否符合JPA标准? (我不这么认为; - )
当然,为什么这个“解决方案”有效?