Hibernate - 双向 @OneToOne

14

我有两个类:User和UserPicture,它们之间存在着一对一的关系。

public class User {
     @Id
     @GeneratedValue(strategy=GenerationType.AUTO)
     @Column(name="id", nullable = false, unique = true)
 private int id;

     private String firstname;

     private String lastname;

     @OneToOne
     @JoinColumn(name = "picture") //field named "picture" in the database
     private UserPicture userPicture;

     ..
}


public class UserPicture {

     @Id
     @GeneratedValue(strategy=GenerationType.AUTO)
     @Column(name="id", nullable = false, unique = true)
     private int id;

     private Blob image;

     @OneToOne
     @JoinColumn(name = "user")
     User user;

'UserPicture'中的'user'会被加载,但是在'User'中的'userPicture'不会被加载 - 我做错了什么?

编辑 必须补充说明,我只是创建了一个UserPicture并将其插入(使用现有的userId) - 也许我需要级联加载'UserPicture'中的'user'吗?

3个回答

21

你需要映射你的类。

public class User {
    ...
    @OneToOne (mappedBy="user")
    private UserPicture userPicture;
    ...
}

public class UserPicture {
    ...
    @OneToOne
    @JoinColumn (name="user")
    private User user;
    ...
}

它有效!谢谢!但是如果我插入一个用户图片,用户将不会被更新吗? - user1731299
@user1731299 把UserUserPicture关联起来所需做的所有事情,就是创建一个UserPicture对象,调用setUser方法将其关联到User上,最后将其持久化到数据库中。 - Pigueiras
前端请求我为用户A添加用户图片。在我的服务中,我重新加载用户A,将此用户设置为我的新UserPicture对象,并创建/插入UserPicture -->表中的字段'picture'保持为空。如果我加载一个用户,则该字段的图片被加载..真的很奇怪。 - user1731299
1
@user1731299 在这个配置中不应该存在 picture 字段。你只需要在 UserPicture 表中引用 user 即可。如果你从数据库中恢复一个用户,Hibernate 将会为你加载 UserPicture 属性,因为这是一对一的关系。希望现在清楚了 :-) - Pigueiras
完全清楚!只有一个问题,能不能使User中的userPicture变成lazy? - user1731299
你确定吗?我发现许多博客和讨论告诉我@OneToOne不支持lazy。我改变了User:@OneToMany(mappedBy = "user", fetch = FetchType.LAZY) private List<UserPicture> pictureList; - user1731299

7
关于您的问题:(因为我没有足够的声誉在评论中回答)
“一切都清楚了!只有一个更多的问题,是否可以使用户图片在用户中变得懒惰? - 用户1731299 2012年10月24日10:44”
是的,可以使它懒惰获取。然而,仅仅说“fetchType=FetchType.Lazy”不起作用。原因是Hibernate需要检查连接的表来查看它是否为null值,或者是否存在记录。由于它是一对一映射,Hibernate认为通过只返回任何数据来节省数据库调用,因为它必须检查它是否为空。这不适用于x到多映射,因为Hibernate知道“多”意味着在另一个表上等待列表......无论是空列表还是已填充列表,它仍然是一个列表。对于单个值,它必须区分实际数据和空值。
解决这个问题的方法是告诉Hibernate始终会有一个值,并且永远不会有null值。知道这一点,Hibernate可以创建占位符,直到到达获取那些数据的时间。您在注释中执行此操作的方式是将“optional = false”添加到@OneToOne注释中。
但要小心!这会带来一些问题;包括我现在试图解决的这个问题(以及我如何偶然发现您在这里的问题)。此optional=false使Hibernate执行一些额外的验证,并似乎让Hibernate困惑了应该如何执行插入。因此,您可能希望远离这种懒惰获取技术。

2
在 One to One 中,即使我们在 JoinColumn 注释中将字段指定为非空,Lazy loading 也能正常工作。但是,在双向 One to One 中,当我们使用 mappedBy='' 的实体时,懒加载不起作用。例如,如果我们有两个实体 Contract 和 House,其中 Contract 表保存了对 House 的外键。当我们在这里使用双向 OneToOne 并尝试加载 contract 时,懒加载起作用(即 House 不会被急切地加载),但是当我们尝试加载 House(使用 House 存储库)时,Contract 总是会被急切地获取。有人知道这是为什么吗?
Public class Contract {
  .....
  @onetoone(lazy)
  @JoinColumn(name='houseid', nullable=false)
  Private House house
  .....
}

Public class House {
  .....
  @onetoone(lazy, mappedBy='house')
  Private Contract contract
  .....
}

我知道这只是一个部分回答,也是一个问题。但它与此处的讨论非常相关。


你应该将你的“答案”重新陈述为一个问题。简短回答:当填充House实体时,Hibernate需要知道“contract”是否为NULL,或者Hibernate是否应该使用House的“代理”对象。为了知道这一点,Hibernate需要检查Contract表并搜索当前的House。如果第二个查询已经检查了表,为什么不立即加载它呢?在最好的情况下,这可以节省Hibernate一个额外的查询(如果您调用house.getContract(),则是相同的查询)。 - Manuel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接