Jon*_*nas 12 java database hibernate jpa
我正在尝试使用JPA/Hibernate设置以下表:
User:
userid - PK
name
Validation:
userid - PK, FK(user)
code
Run Code Online (Sandbox Code Playgroud)
可能有许多用户,每个用户可能有最多一个验证码或没有.
这是我的课程:
public class User
{
@Id
@Column(name = "userid")
@GeneratedValue(strategy = GenerationType.IDENTITY)
protected Long userId;
@Column(name = "name", length = 50, unique = true, nullable = false)
protected String name;
...
}
public class Validation
{
@Id
@Column(name = "userid")
protected Long userId;
@OneToOne(cascade = CascadeType.ALL)
@PrimaryKeyJoinColumn(name = "userid", referencedColumnName = "userid")
protected User user;
@Column(name = "code", length = 10, unique = true, nullable = false)
protected String code;
...
public void setUser(User user)
{
this.user = user;
this.userId = user.getUserId();
}
...
}
Run Code Online (Sandbox Code Playgroud)
我创建了一个用户,然后尝试使用以下代码添加验证代码:
public void addValidationCode(Long userId)
{
EntityManager em = createEntityManager();
EntityTransaction tx = em.getTransaction();
try
{
tx.begin();
// Fetch the user
User user = retrieveUserByID(userId);
Validation validation = new Validation();
validation.setUser(user);
em.persist(validation);
tx.commit();
}
...
}
Run Code Online (Sandbox Code Playgroud)
当我尝试运行它时,我得到一个org.hibernate.PersistentObjectException:传递给persist的分离实体:User
我还尝试在Validation类中使用以下代码:
public void setUserId(Long userId)
{
this.userId = userId;
}
Run Code Online (Sandbox Code Playgroud)
当我创建验证码时,我只是这样做:
Validation validation = new Validation();
validation.setUserId(userId);
em.persist(validation);
tx.commit();
Run Code Online (Sandbox Code Playgroud)
但是,由于User为null,我得到org.hibernate.PropertyValueException:not-null属性引用null或transient值:User.code
非常感谢有关如何最好地解决此问题的任何帮助!
nir*_*ngh 12
我已经能够以纯JPA 2.0的方式解决"具有共享主键的两个表之间的OneToOne"的问题(感谢SOF上的许多现有线程).事实上,JPA有两种方法来处理这个问题.我使用eclipselink作为JPA提供程序,使用MySql作为数据库.再次强调,此处未使用专有的eclipselink类.
第一种方法是在父实体的标识符字段上使用AUTO生成类型策略.
父实体必须包含OneToOne关系中的子实体类型成员(级联类型PERSIST和mappedBy =子实体的父实体类型成员)
@Entity
@Table(name = "USER_LOGIN")
public class UserLogin implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name="USER_ID")
private Integer userId;
@OneToOne(cascade = CascadeType.PERSIST, mappedBy = "userLogin")
private UserDetail userDetail;
// getters & setters
}
Run Code Online (Sandbox Code Playgroud)子实体不得包含标识符字段.它必须包含具有Id,OneToOne和JoinColumn注释的父实体类型的成员.JoinColumn必须指定数据库表的ID字段名称.
@Entity
@Table(name = "USER_DETAIL")
public class UserDetail implements Serializable {
@Id
@OneToOne
@JoinColumn(name="USER_ID")
private UserLogin userLogin;
// getters & setters
}
Run Code Online (Sandbox Code Playgroud)上面的方法在内部使用名为SEQUENCE的默认DB表来将值分配给标识符字段.如果尚未存在,则需要如下创建此表.
DROP TABLE TEST.SEQUENCE ;
CREATE TABLE TEST.SEQUENCE (SEQ_NAME VARCHAR(50), SEQ_COUNT DECIMAL(15));
INSERT INTO TEST.SEQUENCE(SEQ_NAME, SEQ_COUNT) values ('SEQ_GEN', 0);
Run Code Online (Sandbox Code Playgroud)第二种方法是在父实体的标识符字段上使用自定义的TABLE生成类型策略和TableGenerator注释.
除了标识符字段的上述更改外,其他所有内容在父实体中保持不变.
@Entity
@Table(name = "USER_LOGIN")
public class UserLogin implements Serializable {
@Id
@TableGenerator(name="tablegenerator", table = "APP_SEQ_STORE", pkColumnName = "APP_SEQ_NAME", pkColumnValue = "USER_LOGIN.USER_ID", valueColumnName = "APP_SEQ_VALUE", initialValue = 1, allocationSize = 1 )
@GeneratedValue(strategy = GenerationType.TABLE, generator = "tablegenerator")
@Column(name="USER_ID")
private Integer userId;
@OneToOne(cascade = CascadeType.PERSIST, mappedBy = "userLogin")
private UserDetail userDetail;
// getters & setters
}
Run Code Online (Sandbox Code Playgroud)儿童实体没有变化.它与第一种方法相同.
此表生成器方法在内部使用DB表APP_SEQ_STORE将值分配给标识符字段.此表需要创建如下.
DROP TABLE TEST.APP_SEQ_STORE;
CREATE TABLE TEST.APP_SEQ_STORE
(
APP_SEQ_NAME VARCHAR(255) NOT NULL,
APP_SEQ_VALUE BIGINT NOT NULL,
PRIMARY KEY(APP_SEQ_NAME)
);
INSERT INTO TEST.APP_SEQ_STORE VALUES ('USER_LOGIN.USER_ID', 0);
Run Code Online (Sandbox Code Playgroud)如果您使用Hibernate,您也可以使用
public class Validation {
private Long validationId;
private User user;
@Id
@GeneratedValue(generator="SharedPrimaryKeyGenerator")
@GenericGenerator(name="SharedPrimaryKeyGenerator",strategy="foreign",parameters = @Parameter(name="property", value="user"))
@Column(name = "VALIDATION_ID", unique = true, nullable = false)
public Long getValidationId(){
return validationId;
}
@OneToOne
@PrimaryKeyJoinColumn
public User getUser() {
return user;
}
}
Run Code Online (Sandbox Code Playgroud)
Hibernate将确保Validation的ID与User实体集的ID相同.
您使用的是 JPA 还是 JPA 2.0?
如果 Validation PK 是对 User 的 FK,那么您不需要验证类中的 Long userId 属性,而是@Id单独进行注释。这将是:
Public class Validation
{
@Id
@OneToOne(cascade = CascadeType.ALL)
@PrimaryKeyJoinColumn(name = "userid", referencedColumnName = "userid")
protected User user;
@Column(name = "code", length = 10, unique = true, nullable = false)
protected String code;
...
public void setUser(User user)
{
this.user = user;
this.userId = user.getUserId();
}
...
}
Run Code Online (Sandbox Code Playgroud)
尝试一下并告诉我们您的结果。
| 归档时间: |
|
| 查看次数: |
20783 次 |
| 最近记录: |