我有我的數據庫中有2個實體與一對一的一個定向映射: 用戶和PasswordResetToken。這背後的想法是每次用戶請求重置密碼並僅存儲最新密碼時創建新的令牌。休眠一對一DTO實體人口
下面是我的實體:
@Entity
@Table(name = "USERS")
@Getter @Setter
public class User implements Serializable {
@Id
@Column(name = "ID")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "usersSeq")
@SequenceGenerator(name = "usersSeq", sequenceName = "SEQ_USERS", allocationSize = 1)
private long id;
@Column(name = "NAME")
private String name;
@Column(name = "PASSWORD")
private String password;
@Column(name = "EMAIL")
private String email;
@Column(name = "ROLE")
private Integer role;
}
///...
@Entity
@Table(name = "PASSWORD_RESET_TOKENS")
@Getter
@Setter
public class PasswordResetToken implements Serializable {
private static final int EXPIRATION = 24;
@Column(name = "TOKEN")
private String token;
@Id
@OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinColumn(nullable = false, name = "user_id")
private User user;
@Column(name = "EXPIRY_DATE")
private Instant expiryDate;
public PasswordResetToken() {
}
public void setExpiryDate(ZonedDateTime expiryDate) {
this.expiryDate = expiryDate.plus(EXPIRATION, ChronoUnit.HOURS).toInstant();
}
}
另外,我對他們倆創造的DTO通過他們在我的應用程序。 代碼片段:
@Getter @Setter
public class PasswordResetTokenModel {
private String token;
private ZonedDateTime expiryDate;
private UserModel user;
}
的usermodel也可用於春季安全
@Getter
@Setter
public class UserModel extends User {
public UserModel(String username, String password, Collection<? extends GrantedAuthority> authorities) {
super(username, password, authorities);
}
private long id;
private String name;
public String getEmail() {
return this.getUsername();
}
}
人口,我創建了2個populators:
@Component
public class UserPopulatorImpl implements UserPopulator {
@Autowired
UserDetailsService userDetailsService;
@Override
public UserModel populateToDTO(User user) {
UserModel userModel = new UserModel(user.getEmail(), user.getPassword(), userDetailsService.getAuthorities(user.getRole()));
userModel.setId(user.getId());
return userModel;
}
@Override
public User populateToDAO(UserModel userModel) {
User user = new User();
user.setEmail(userModel.getEmail());
user.setName(userModel.getName());
user.setPassword(userModel.getPassword());
//TODO: change it!
user.setRole(1);
return user;
}
}
//...
@Component
public class PasswordResetTokenPopulatorImpl implements PasswordResetTokenPopulator {
@Autowired
UserPopulator userPopulator;
@Override
public PasswordResetTokenModel populateToDTO(PasswordResetToken passwordResetToken) {
PasswordResetTokenModel passwordResetTokenModel = new PasswordResetTokenModel();
passwordResetTokenModel.setUser(userPopulator.populateToDTO(passwordResetToken.getUser()));
passwordResetTokenModel.setToken(passwordResetToken.getToken());
passwordResetTokenModel.setExpiryDate(ZonedDateTime.ofInstant(passwordResetToken.getExpiryDate(), ZoneId.systemDefault()));
return passwordResetTokenModel;
}
@Override
public PasswordResetToken populateToDAO(PasswordResetTokenModel passwordResetTokenModel) {
PasswordResetToken passwordResetToken = new PasswordResetToken();
passwordResetToken.setExpiryDate(passwordResetTokenModel.getExpiryDate());
passwordResetToken.setUser(userPopulator.populateToDAO(passwordResetTokenModel.getUser()));
passwordResetToken.setToken(passwordResetTokenModel.getToken());
return passwordResetToken;
}
}
我節省使用
對象sessionFactory.getCurrentSession().saveOrUpdate(token);
當我使用此代碼,我發現了以下異常
object references an unsaved transient instance - save the transient instance before flushing: com.demo.megaevents.entities.User
目前有2個問題在此代碼:
- 好像Cascade.ALL我OneToOne映射不工作。如果 我在令牌類中創建單獨的主鍵一切都按預期工作幾乎 ,但存儲在DB中的每個創建的令牌(更像是 OneToMany關係),但是我想避免它,因爲我需要存儲 每個用戶只有一個令牌在我DB
- 我不喜歡在populator中使用new,因爲它迫使hibernate在刷新會話時創建新對象。然而,我也不想做另一個選擇從數據庫中獲取這些數據,因爲之前提到的populator我已經做了這個查詢來獲取它,我認爲這是一個開銷。
此外,我真的想擁有DTO,我不想刪除DTO層。
所以,我的問題:
- 什麼是處理DTO和實體之間人口的正確方法是什麼?
- 我的解決方案有沒有其他改進(可能是架構)?
非常感謝。
也許我不是正確理解你的應用程序,但是如果你在Token類中添加單獨的主鍵,刪除'@JoinColumn(nullable = false,name =「user_id」)'並且添加你的用戶類'@OneToOne(mappedBy =「user」,fetch = FetchType.EAGER,cascade = CascadeType.ALL)PasswordResetToken標記;' – lenach87
@ lenach87,我不希望用戶知道一個標記,但其他方式。 – Selik