首先,我知道这不应该是一个解决方案,但我需要以这种方式解决问题。
我有一个非常罕见的 OneToOne关系(DB返回两行而不是一行)。我需要强制这种关系,就像这个特定的Hibernate查询的 LIMIT 1 一样。
@Entity
@Table(name="contact", uniqueConstraints = @UniqueConstraint(columnNames="user_id"))
public class ContactDTO implements Serializable {
(...)
// Force this relation
@OneToOne(cascade = CascadeType.REFRESH, fetch = FetchType.LAZY, optional = true)
@JoinColumn(name = "user_id", unique = true, insertable = false, updatable = false)
public UserDTO getBaseUser() {
return baseUser;
}
public void setBaseUser(UserDTO baseUser) {
this.baseUser = baseUser;
}
@Column(name = "user_id", unique = true)
public Integer getUserId() {
return this.userId;
}
@Entity
@Table(name = "base_user")
public class UserDTO implements Serializable {
(...)
@OneToOne(fetch = FetchType.LAZY, mappedBy = "baseUser")
public ContactDTO getContact() {
return contact;
}
public void setContact(ContactDTO contact) {
this.contact = contact;
}
当我得到两行(最多)时,Hibernate会抛出以下异常:
org.hibernate.HibernateException: More than one row with the given identifier was found
这是可能的还是我真的需要将这种关系变成@OneToMany?
注意: Hibernate 3.3,遗憾的是我无法使用JoinColumnsOrFormula。
感谢您的帮助! 最好的问候。
答案 0 :(得分:0)
如果您收到的重复记录超过其最可能意味着数据库中的关系可能不是1:1。您需要添加数据库约束来强制执行此关系或将注释更改为1:many。值得注意的是@OneToOne注释不会在数据库中强制执行任何操作,它只是定义了Hibernate期望关系的内容,这就是为什么它会在您收到多个记录时抛出错误。
检查此帖子的答案,了解您的关系在数据库中的外观:
答案 1 :(得分:0)
要实现这一点,您可以使用视图。
假设您SOME_TABLE
有两列REAL_ID
和BAD_ID
。第一个是唯一的,第二个是你破碎的非独特列。
只需创建视图,例如:
select * from SOME_TABLE where REAL_ID in (
select min(REAL_ID) from SOME_TABLE group by BAD_ID
)
这基本上是您的原始表减去重复BAD_ID
值的记录。然后在hibernate映射中使用此视图而不是原始表。
显然这是一个黑客,所以我不能保证它的性能,但它应该允许你使用@OneToOne绑定。最大的缺点是默认情况下这将是只读映射(可能会随instead of
triggers更改)。
编辑有些数据库允许简单的视图可更新,因此它可以在没有任何触发器的情况下工作。
您还可以直接从查询中查看生成实体。