有人能告诉我Hibernate是否支持关联作为实体的密钥?我认为这将得到支持,但是我在使用任何代表这种方式的映射时遇到了很多麻烦。特别是,使用下面的直接映射:
@Entity
public class EntityBar
{
@Id
@OneToOne(optional = false, mappedBy = "bar")
EntityFoo foo
// other stuff
}
我得到一个org.hibernate.MappingException:“无法确定类型:EntityFoo,在表:ENTITY_BAR,对于列:[org.hibernate.mapping.Column(foo)]”
潜入代码似乎ID始终被视为值类型;即“任何通过值而不是通过引用持久化的东西。它本质上是一个Hibernate类型,连同零个或多个列。”我可以通过声明它的序列化来使我的EntityFoo成为一个值类型,但我不认为这会导致正确的结果。
我原本以为Hibernate会认为列的类型是整数(或者父类ID的实际类型),就像它与普通的一对一链接一样,但这并不是'当我也宣布它是一个ID时,似乎开始了。尝试将@OneToOne与@Id结合起来,我是否超越了可能的范围?如果是这样,那么如何合理地建立这种关系呢?
答案 0 :(得分:2)
如果目标是拥有共享主键,那么(受 Java Persistence With Hibernate 样本的启发并在宠物数据库上测试):< / p>
@Entity
public class User {
@Id
@GeneratedValue
private Long id;
@OneToOne(cascade = CascadeType.ALL)
@PrimaryKeyJoinColumn
private Address shippingAddress;
//...
}
这是首先插入并获取生成ID的“父”类。 Address
看起来像这样:
@Entity
public class Address implements Serializable {
@Id @GeneratedValue(generator = "myForeignGenerator")
@org.hibernate.annotations.GenericGenerator(
name = "myForeignGenerator",
strategy = "foreign",
parameters = @Parameter(name = "property", value = "user")
)
@Column(name = "ADDRESS_ID")
private Long id;
@OneToOne(mappedBy="shippingAddress")
@PrimaryKeyJoinColumn
User user;
//...
}
使用上述实体,以下似乎表现得如预期:
User newUser = new User();
Address shippingAddress = new Address();
newUser.setShippingAddress(shippingAddress);
shippingAddress.setUser(newUser); // Bidirectional
session.save(newUser);
保存Address
时,插入的主键值与User
属性引用的user
实例的主键值相同。
加载User
或Address
也是有效的。
如果我错过了什么,请告诉我。
PS:严格回答问题,根据Primary Keys through OneToOne Relationships:
JPA 1.0不允许在OneToOne或ManyToOne上使用@Id,但JPA 2.0允许使用@Id。
但,符合JPA 1.0标准的Hibernate版本
允许在
@Id
或OneToOne
映射*上使用ManyToOne
注释。
我无法使用Hibernate EM 3.4(它适用于Hibernate EM 3.5.1,即JPA 2.0实现)。也许我做错了什么。
无论如何,使用共享主键似乎提供了有效的解决方案。
答案 1 :(得分:1)
是的,这是可能的。
使用Driver和DriverId类作为驱动程序的ID,查看以下示例。
@Entity
public class Drivers {
private DriversId id; //The ID which is located in another class
public Drivers() {
}
@EmbeddedId
@AttributeOverrides({
@AttributeOverride(name = "personId", column = @Column(name = "person_id", nullable = false))})
@NotNull
public DriversId getId() {
return this.id;
}
//rest of class
}
这里我们使用personId作为Driver
的id和DriversId类:
//composite-id class must implement Serializable
@Embeddable
public class DriversId implements java.io.Serializable {
private static final long serialVersionUID = 462977040679573718L;
private int personId;
public DriversId() {
}
public DriversId(int personId) {
this.personId = personId;
}
@Column(name = "person_id", nullable = false)
public int getPersonId() {
return this.personId;
}
public void setPersonId(int personId) {
this.personId = personId;
}
public boolean equals(Object other) {
if ((this == other))
return true;
if ((other == null))
return false;
if (!(other instanceof DriversId))
return false;
DriversId castOther = (DriversId) other;
return (this.getPersonId() == castOther.getPersonId());
}
public int hashCode() {
int result = 17;
result = 37 * result + this.getPersonId();
return result;
}
}
答案 2 :(得分:0)
您可以通过在EntityFoo和EntityBar之间共享主键来完成此操作:
@Entity
public class EntityBar
{
@Id @OneToOne
@JoinColumn(name = "foo_id")
EntityFoo foo;
// other stuff
}
@Entity
public class EntityFoo
{
@Id @GeneratedValue
Integer id;
// other stuff
}
答案 3 :(得分:0)
您必须在此处使用@EmbeddedId
代替@Id
。
EntityFoo
应为Embeddable
。
另一种方法是放置一个整数,OneToOne
updateble
和instertable
设置为false.