当前位置: 首页 > 知识库问答 >
问题:

Hibernate:如何使用父对象的自动生成ID作为外键级联嵌入式对象

颛孙航
2023-03-14

问题:

在Hibernate(JPA 2.0)中,在创建父对象时,如何创建具有@OneToOne关系的嵌入式对象?

期望值:

当我创建一个用户时,我希望它能自动创建相应的属性,将用户自动生成的id作为属性的对象id

现实:

当我尝试创建用户时,我得到以下异常:

javax.persistence.PersistenceException: org.hibernate.PropertyValueException: not-null property references a null or transient value: com.api.user.PropertyEntity.objectId

数据库表:

我有两个MySQL表:usersproperties

users
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1  | foo      | bar      |
+----+----------+----------+
| 2  | goo      | baz      |
+----+----------+----------+
| 3  | woo      | hah      |
+----+----------+----------+

properties
+----+-----------+-------------+---------+-----------+
| id | object_id | object_type | propkey | propvalue |
+----+-----------+-------------+---------+-----------+
| 1  | 1         | user        | sso     | true      |
+----+-----------+-------------+---------+-----------+
| 2  | 1         | user        | ssoid   | foobar    |
+----+-----------+-------------+---------+-----------+
| 3  | 2         | user        | sso     | false     |
+----+-----------+-------------+---------+-----------+
| 4  | 2         | user        | ssoid   | null      |
+----+-----------+-------------+---------+-----------+
| 5  | 3         | user        | sso     | false     |
+----+-----------+-------------+---------+-----------+
| 6  | 3         | user        | ssoid   | null      |
+----+-----------+-------------+---------+-----------+

Java实体:

一个用户可以有多个属性,但每个属性都与该用户有@OneToOne关系,并且这种关系是单向的(即用户创建其属性,而不是相反)。

Java中的用户实体如下所示:

@Entity
@Table(name = "users")
public class UserEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id", nullable = false)
    private Integer id;

    @Column(name = "username", nullable = false)
    private String userName;

    @Column(name = "password", nullable = false)
    private String password;

    @OneToOne
    @Cascade(value = { org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.DELETE })
    @JoinColumnsOrFormulas(value={
            @JoinColumnOrFormula(column=
                   @JoinColumn(name = "id", referencedColumnName = "object_id", insertable=false, updatable=false, nullable = false)
            ),
            @JoinColumnOrFormula(formula=
                    @JoinFormula(referencedColumnName="object_type", value="'user'")
            ),
            @JoinColumnOrFormula(formula=
                    @JoinFormula(referencedColumnName="propkey", value="'sso'")
            )
    })
    private PropertyEntity isSso;

    @OneToOne
    @Cascade(value = { org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.DELETE })
    @JoinColumnsOrFormulas(value={
            @JoinColumnOrFormula(column=
                    @JoinColumn(name = "id", referencedColumnName = "object_id", insertable=false, updatable=false, nullable = false)
            ),
            @JoinColumnOrFormula(formula=
                    @JoinFormula(referencedColumnName="object_type", value="'user'")
            ),
            @JoinColumnOrFormula(formula=
                    @JoinFormula(referencedColumnName="propkey", value="'ssoid'")
            )
    })
    private PropertyEntity ssoId;

    // Getters & Setters
}

属性实体如下所示:

@Entity
@Table(name = "properties")
public class PropertyEntity {

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

    @Column(name = "object_id", nullable = false)
    private Integer objectId;

    @Column(name = "object_type", nullable = false)
    private String objectType;

    @Column(name = "propkey", nullable = false)
    private String name;

    @Column(name = "propvalue", nullable = false)
    private String value;

    // Getters & Setters
}

共有1个答案

高承望
2023-03-14

与大多数与Hibernate注释相关的问题一样,我解决了这个问题,方法是完全消除它们,并以老式的方式进行(在事务中分别查询创建/更新用户,然后创建/更新每个用户属性记录)。

如果有人有一个有效的Hibernate解决方案,我很乐意接受这个答案。

 类似资料:
  • 我想要的操作:如果需要,在子表中插入一行会自动在父表中插入一行,否则将父表中现有行的id用作子表中插入行的外键。 我想知道是否有任何方法可以使用一个语句。 我使用Hibernate与Java和SQLite。以下是我关于数据库和配置的详细信息: 表家长: 表儿童: POJO家长: POJO儿童: 父母亲哈佛商学院: 小孩哈佛商学院: 现在,如果父项(具有相同的“描述”)不存在,则父项将与子项一起插入

  • 问题内容: 我知道这听起来是不可能的,但是我的老板告诉我,我必须通过jQuery的AJAX发布调用发送JSON,并且必须具有重复的键。问题是,如果我写这样的话: ,jQuery会将请求发送为 所有这些都是因为Javascript会覆盖具有相同名称的属性。JSON对象是动态生成的,不允许在其中使用数组。有人可以告诉我如何生成具有重复键的JSON对象吗? 非常感谢您的帮助! 问题答案: 据我所知,实际

  • 问题内容: 我已决定在多个hibernate实体/域对象的equals()和hashcode()中使用自动生成的ID。 但是,许多网站都说您永远不要这样做,因为存在在比较对象或使用哈希码的过程中将对象第一次持久保存到数据库的风险。 我的观点是,在大多数用例中,这比其他任何要更改的领域都不太可能。 单个域对象在首次创建时就会生成一次ID,而几乎每个其他字段都有机会在正常业务流程中进行更改(甚至可以更

  • 问题内容: 我对级联=“删除”的工作方式感到困惑。我在“城市”映射文件中以以下方式定义了映射: 类客户具有类城市的外键。 因此,当我运行时: 是否还应该删除所有客户端,还是必须以某种方式处理它?我是否将查询作为方法参数正确传递给会话的delete()方法?谢谢你的帮助。最好的问候,混蛋。 问题答案: 我对cascade =“ delete”的工作方式有些困惑(…) 级联操作意味着,如果您是父母,则

  • 问题内容: 我有一个以前被保留的实体,并且与另一个实体有关系。为了添加新实体,我只需将新实体添加到托管对象中,并用于保留更改。有没有一种方法可以获取新创建的对象的ID或获取我用于合并以更新其ID的原始(非托管)对象? 在伪代码中,我希望发生以下情况: 将为合并实体返回新副本 旧副本将针对新实体进行更新 示例:父级A,id = 13子级B,id = 0 从本质上讲,我想在父级上发布a ,但在子级上级

  • 下面列出的代码不允许创建新书对象,即使有构造函数也不行。我得到了一个NullPointerException,我想这是因为我在初始化对象时出错了。最终目标是创建一个程序,询问用户是否要创建新的图书对象,当用户说“是”时,它会返回并创建另一个图书对象。