我认为我的用户和权限设计存在缺陷。登录工作正常,但我的create_user页面上有org.hibernate.TransientPropertyValueException
。
当我从表单添加新用户时,使用以下代码:
public fr.cnamts.navigo.domain.User create(UserCreateForm form) {
fr.cnamts.navigo.domain.User user = new fr.cnamts.navigo.domain.User();
user.setUsername(form.getEmail());
user.setPassword(new BCryptPasswordEncoder().encode(form.getPassword()));
user.setEnabled(true);
Authorities role = new Authorities();
role.setUser(user);
role.setAuthority(form.getRole());
role = authoritiesRepository.save(role);
user.addAuthorities(role);
user = userRepository.save(user);
return user;
}
org.hibernate.TransientPropertyValueException
上有一个save(role)
。
当局类:
@Entity
@Table(name="authorities", uniqueConstraints = @UniqueConstraint(
columnNames = { "authority", "username" }))
public class Authorities {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "authority_id",
unique = true, nullable = false)
private Integer id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "username", nullable = false)
private User user;
@Column(name = "authority", nullable = false, length = 45)
private String authority;
public Authorities() {
}
public Authorities(User user, String role) {
this.user = user;
this.authority = role;
}
public void setUser(User user) {
this.user = user;
if (!user.getAuthorities().contains(this)) { // warning this may cause performance issues if you have a large data set since this operation is O(n)
user.getAuthorities().add(this);
}
} // assume other basic getters and setters
用户一:
@Entity
@Table(name = "users")
public class User {
@Id
@Column(name = "username", nullable = false, unique = true, length = 60)
private String username;
@Column(name = "password", nullable = false, length = 60)
private String password;
@Column(name = "enabled", nullable = false)
private boolean enabled;
// private boolean tokenExpired;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "user")
private Set<Authorities> authorities;
public User() {
this.authorities = new HashSet<Authorities>();
}
public User(String username, String password, boolean enabled) {
this.username = username;
this.password = password;
this.enabled = enabled;
this.authorities = new HashSet<Authorities>();
}
public User(String username, String password, boolean enabled,
Set<Authorities> userRoles) {
this.username = username;
this.password = password;
this.enabled = enabled;
if (userRoles != null) {
this.authorities = userRoles;
} else {
this.authorities = new HashSet<Authorities>();
}
}
public void addAuthorities(Authorities role) {
this.authorities.add(role);
if (role.getUser() != this) {
role.setUser(this);
}
}
public void addAuthorities(String role, User user) {
this.addAuthorities(new Authorities(user, role));
}
当我添加新用户时,我需要用户的角色/权限,但是要创建权限对象,我需要用户实例。
以下是控制台跟踪的摘录:
Hibernate: select user0_.username as username1_1_, user0_.enabled as enabled2_1_, user0_.password as password3_1_ from users user0_ where user0_.username=?
Hibernate: select nextval ('hibernate_sequence')
Hibernate: select user_.username, user_.enabled as enabled2_1_, user_.password as password3_1_ from users user_ where user_.username=?
2015-12-15 16:21:26.390 WARN 6832 --- [nio-8081-exec-3] o.h.a.i.UnresolvedEntityInsertActions : HHH000437: Attempting to save one or more entities that have a non-nullable association with an unsaved transient entity. The unsaved transient entity must be saved in an operation prior to saving these dependent entities.
Unsaved transient entity: ([fr.cnamts.navigo.domain.User#datm.flux1@cnamts.fr])
Dependent entities: ([[fr.cnamts.navigo.domain.Authorities#4]])
Non-nullable association(s): ([fr.cnamts.navigo.domain.Authorities.user])
2015-12-15 16:21:26.398 ERROR 6832 --- [nio-8081-exec-3] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.TransientPropertyValueException: Not-null property references a transient value - transient instance must be saved before current operation : fr.cnamts.navigo.domain.Authorities.user -> fr.cnamts.navigo.domain.User; nested exception is java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: Not-null property references a transient value - transient instance must be saved before current operation : fr.cnamts.navigo.domain.Authorities.user -> fr.cnamts.navigo.domain.User] with root cause
org.hibernate.TransientPropertyValueException: Not-null property references a transient value - transient instance must be saved before current operation : fr.cnamts.navigo.domain.Authorities.user -> fr.cnamts.navigo.domain.User
at org.hibernate.action.internal.UnresolvedEntityInsertActions.checkNoUnresolvedActionsAfterOperation(UnresolvedEntityInsertActions.java:137) ~[hibernate-core-4.3.11.Final.jar:4.3.11.Final]
我想我在getter / setter方面或构造方面缺少一些东西。数据库端的对象似乎很好。这是创建代码(postgresql):
create table users (
username varchar(50) primary key,
password varchar(255) not null,
enabled boolean not null DEFAULT TRUE
);
create table authorities (
authority_id SERIAL,
username varchar(50) not null,
authority varchar(50) not null,
PRIMARY KEY (authority_id),
CONSTRAINT uni_username_authority UNIQUE(authority,username),
constraint fk_roles_users foreign key (username) references users (username)
);
答案 0 :(得分:1)
由于authority表具有users表的外键,因此必须在Authority之前保存User。
您可以让Hibernate在通过向关联添加级联注释来持久保存权限之前保留关联的用户:
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name = "username", nullable = false)
private User user;
https://docs.oracle.com/javaee/5/api/javax/persistence/ManyToOne.html