【问题标题】:How to add element to bidirectional relationship correctly? I am getting collection is evicted如何正确地将元素添加到双向关系?我正在收集被驱逐
【发布时间】:2021-03-10 20:57:48
【问题描述】:

我有以下课程

public class User {

    @OneToMany(
            fetch = FetchType.EAGER,
            mappedBy = "user",
            cascade = CascadeType.ALL
    )
    private Set<UserSession> sessions;


    public UserSession login() {
        UserSession session = new UserSession();
        session.setUser(this);
        session.persistAndFlush();
        this.persistAndFlush();
        return session;
    }


....

public class UserSession {

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id")
    protected User user;

如您所见,我正在从它的一侧添加会话。有时在其他时候我得到了

caused by: org.hibernate.HibernateException: collection was evicted

如何正确做?

【问题讨论】:

    标签: java jpa one-to-many many-to-one bidirectional-relation


    【解决方案1】:

    以双向关系添加元素,

    • 在父类中创建一个辅助方法,用于添加或删除子实体。
    • 创建子实体并使用辅助方法将其添加到父集合中
    • 保存子实体

    示例代码:

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

    【讨论】:

      猜你喜欢
      • 2019-08-18
      • 2018-10-28
      • 1970-01-01
      • 2017-02-25
      • 2015-10-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多