【问题标题】:JPA/Hibernate - shared primary keyJPA/Hibernate - 共享主键
【发布时间】:2012-09-02 08:28:45
【问题描述】:

我想用共享主键创建双向的一对一关系。

正如这里所说的JPA Hibernate One-to-One relationship 我有:

@Entity
public class UserProfileInformation {

    @Id
    @GeneratedValue(generator = "customForeignGenerator")
    @org.hibernate.annotations.GenericGenerator(
        name = "customForeignGenerator",
        strategy = "foreign",
        parameters = @Parameter(name = "property", value = "userEntity")
    )
    long id;

    private long itemsPerPage;

    @OneToOne(mappedBy="userProfileInformation")
    private UserEntity userEntity;
...}

@Entity
@Table(name = "UserTable")
public class UserEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String publicName;

    private String password;

    private String emailAddress;

    private String name; 

    private boolean active;

    @OneToOne(cascade=CascadeType.ALL)
    @PrimaryKeyJoinColumn
    private UserProfileInformation userProfileInformation;
...}

现在,当我尝试将我的用户保存在数据库中时,我得到了org.hibernate.id.IdentifierGenerationException: null id generated for:class pl.meble.taboret.model.UserProfileInformation。是因为,当 userProfileInformation 被持久化到数据库 userEntity 时没有生成 id 吗?

另外,在我的示例中,如何创建与共享主键的双向关系?

编辑: 请求代码,这是一个简单的控制器来测试持久化用户实体的操作。

@Controller
@RequestMapping("/test")
public class TestController {
    @Autowired
    UserDao userDao;

    @RequestMapping(method= RequestMethod.GET)
    public String t(Model model){
        UserEntity entity=new UserEntity();
        entity.setActive(false);
        entity.setEmailAddress("a");
        entity.setName("name");
        entity.setPassword("qqq");
        entity.setPublicName("p");
        UserProfileInformation p = new UserProfileInformation(entity);
        entity.setUserProfileInformation(p);
        userDao.addUser(entity);
        return "login";
    }
}

【问题讨论】:

  • 显示您在其中创建/保存 UserProfileInformation 实体的代码。您是否正确设置了 userEntity 引用?还要检查将类型从 long 更改为 Long 是否有效。
  • 我将代码添加到已编辑的第一篇文章中,此外,将类型从 long 更改为 Long 并没有解决问题。
  • 看看这个 - stackoverflow.com/questions/4027623/…。我认为这与哪一方是拥有方有关-您可能需要交换 mappedBy 和 PrimaryKeyJoinColumn
  • 我读了这篇文章,但问题是,mapped by 指向标记关联的非拥有方。对我来说很奇怪,我应该在 UserEntity 端使用 mapped by,这是 imo 的拥有端。可以这么说,我就是无法理解这一点。

标签: java hibernate sqlite jpa jpa-2.0


【解决方案1】:

我认为问题在于 id 生成策略。对于休眠 @GeneratedValue(strategy = GenerationType.AUTO) 转换为 native 标识符生成。这意味着 hibernate 期望 UserTable 有一个 identity id 字段。

我不确切知道SQLite 在身份列方面的工作原理,但似乎与this SO question 有点不同(请参阅第二个答案)。

无论如何,如果您计划在多个数据库上运行您的应用程序,那么从GenerationType.AUTO 更改id 生成策略并使用休眠增强生成器:SequenceStyleGeneratorTableGenerator 会更好。请参阅休眠文档中的this link

编辑:

我尝试重现您的问题,SQLite 方言似乎不在官方支持的hibernate dialects 中。同时,我使用H2 embeded database 测试了您的案例,它按预期工作:您的映射是正确的。

如果你使用的是非官方的 SQLite 方言,这可能是该方言的错误。

【讨论】:

  • 我不知道这是否是严格的 id 生成问题。在我没有 UserProfileInformation 类之前,我可以毫无问题地坚持 UserEntity。
  • 如果启用休眠 sql 日志,在持久化用户实体时会看到哪些 sql?就在异常之前。
  • 我启用了 sql 日志,没有可见的 sql。例外是null id generated for:class pl.meble.taboret.model.UserProfileInformation,因为我正在保存UserEntity,并且我所有的Cascade,Hiberante想先存储UserProfileInformation,但他不能,因为相应的UserEntity中没有id。当我从两个类中删除 @GeneratedValue 并在 UserEntity 中手动设置 id 时,一切正常。
  • 另外,正如我在之前的评论中所说,如果我手动设置 UserEntity 的 Id,我会得到这个 sql 日志Hibernate: /* insert pl.meble.taboret.model.UserProfileInformation */ insert into UserProfileInformation (itemsPerPage, id) values (?, ?) Hibernate: /* insert pl.meble.taboret.model.UserEntity */ insert into UserTable (active, emailAddress, name, password, publicName, id) values (?, ?, ?, ?, ?, ?) ,所以我们在这里看到 UserProfileInformation 是首先存储的。
  • 什么hibernate和SQLite版本?我会建立一个小项目来测试你的用例。
猜你喜欢
  • 2011-06-12
  • 1970-01-01
  • 2021-05-26
  • 1970-01-01
  • 2011-02-18
  • 1970-01-01
  • 1970-01-01
  • 2012-12-26
  • 2018-10-19
相关资源
最近更新 更多