Java Hibernate:如何将嵌入式对象与父对象级联';s自动生成的ID作为外键

Java Hibernate:如何将嵌入式对象与父对象级联';s自动生成的ID作为外键,java,mysql,hibernate,jpa,one-to-one,Java,Mysql,Hibernate,Jpa,One To One,问题: 在Hibernate(JPA2.0)中,当我创建父对象时,如何创建具有@OneToOne关系的嵌入式对象 期望值: 当我创建一个用户时,我希望它自动创建相应的属性,并将用户自动生成的id作为属性的对象id 现实: 尝试创建用户时,出现以下异常: javax.persistence.PersistenceException: org.hibernate.PropertyValueException: not-null property references a null or transi

问题:

在Hibernate(JPA2.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表:
users
properties

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
}
属性
实体如下所示:

@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
}

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


如果有人有一个Hibernate解决方案可以使用,我很乐意接受这个答案。

为什么不能用用户的地图替换您的PropertyEntity,并将其作为
@MappedCollection
存储在
PropertyEntity
表中?这将消除所有这些麻烦,是一个更干净的设计。每个用户都有自己的属性映射,并且映射不能有重复的键。我知道这似乎没有什么帮助,但你似乎试图强迫Hibernate去做一些它不是设计用来做的事情。您是否在别处使用
属性实体
?什么“嵌入”对象?我看不到。没有@Embeddedusage@JamesMassey谢谢你的回复!我开始阅读@MappedCollection上的文档,但有一种感觉,它可能在这里不起作用。也许你可以举个例子?我正在处理一个遗留数据库,
properties
表用于存储的不仅仅是
user
属性,因此出现了
object\u type
列。@NeilStockton我选择了“嵌入式”一词来描述
PropertyEntity
对象包含在
UserEntity
对象中的事实,不知道@Embedded注释。我想,这个词选得不好。抱歉,如果这引起了任何混乱。