要在双向关系中添加元素,
- 在父类中创建一个辅助方法来添加或删除子实体。
- 创建子实体并使用辅助方法将其添加到父集合
- 保存子实体
示例代码:
@Getter
@Setter
@Entity
class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<UserSession> userSessions = new HashSet<>();
public void addNewSession(UserSession userSession) {
this.userSessions.add(userSession);
userSession.setUser(this);
}
public void removeSession(UserSession userSession) {
this.userSessions.remove(userSession);
userSession.setUser(null);
}
}
完整的工作代码:
package com.example.demo;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.*;
import org.hibernate.annotations.ResultCheckStyle;
import org.hibernate.annotations.SQLDelete;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.data.repository.CrudRepository;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
@RestController
@RequestMapping("/users")
@EnableTransactionManagement
public class UserAndSessionsController {
private final UserService userService;
@Autowired
public UserAndSessionsController(UserService userService) {
this.userService = userService;
}
@GetMapping
public Iterable<User> list() {
return userService.list();
}
@PostMapping
public User create(@RequestBody User user) {
return userService.save(user);
}
@GetMapping("/sessions")
public Iterable<UserSession> sessions(@RequestParam("userId") Integer userId) {
return userService.getUserSessions(userId);
}
@PostMapping(path = "login")
public UserSession login(@RequestBody User user) throws Throwable {
return userService.createNewLoginSession(user);
}
@PostMapping(path = "logout")
public UserSession logout(@RequestBody UserSessionsDto userSessionsDto) throws Throwable {
return userService.invalidateLoginSession(userSessionsDto.getUser(), userSessionsDto.getUserSession());
}
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
}
@ToString
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
class UserSessionsDto {
private User user;
private UserSession userSession;
}
@Getter
@Setter
@Entity
class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<UserSession> userSessions = new HashSet<>();
public void addNewSession(UserSession userSession) {
this.userSessions.add(userSession);
userSession.setUser(this);
}
public void removeSession(UserSession userSession) {
this.userSessions.remove(userSession);
userSession.setUser(null);
}
}
@Getter
@Setter
@Entity
@SQLDelete(sql = "update USER_SESSION set valid = false where id = ?", check = ResultCheckStyle.COUNT)
class UserSession {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String SessionId;
private boolean valid;
@JsonIgnore
@ManyToOne(fetch = FetchType.LAZY, optional = false)
private User user;
}
@Service
class UserService {
private final UserRepository userRepository;
private final UserSessionRepository userSessionRepository;
@Autowired
UserService(UserRepository userRepository, UserSessionRepository userSessionRepository) {
this.userRepository = userRepository;
this.userSessionRepository = userSessionRepository;
}
@Transactional
public User save(User user) {
return userRepository.save(user);
}
@Transactional(readOnly = true)
public Iterable<User> list() {
return userRepository.findAll();
}
@Transactional(readOnly = true)
public Iterable<UserSession> getUserSessions(Integer userId) {
// return userRepository.findById(userId)
// .map(User::getUserSessions)
// .orElse(Collections.emptySet());
return userSessionRepository.findUserSessionsByUser_Id(userId);
}
@Transactional
public UserSession createNewLoginSession(User user) throws Throwable {
final User dbUser = userRepository
.findById(user.getId())
.orElseThrow(() -> new RuntimeException("User : " + user.getName() + " not found"));
final UserSession userSession = new UserSession();
userSession.setSessionId(UUID.randomUUID().toString());
userSession.setValid(true);
dbUser.addNewSession(userSession);
userSessionRepository.save(userSession);
return userSession;
}
@Transactional
public UserSession invalidateLoginSession(User user, UserSession userSession) throws Throwable {
final User dbUser = userRepository
.findById(user.getId())
.orElseThrow(() -> new RuntimeException("User : " + user.getName() + " not found"));
final UserSession dbUserSession = userSessionRepository
.findById(userSession.getId())
.orElseThrow(() -> new RuntimeException("UserSession : " + userSession.getSessionId() + " not found"));
dbUser.removeSession(dbUserSession);
userSessionRepository.delete(dbUserSession);
return dbUserSession;
}
}
@Repository
interface UserRepository extends CrudRepository<User, Integer> {
}
@Repository
interface UserSessionRepository extends CrudRepository<UserSession, Integer> {
Iterable<UserSession> findUserSessionsByUser_Id(Integer userId);
}