【问题标题】:@OneToOne mapping isnt working in my Java Spring project@OneToOne 映射在我的 Java Spring 项目中不起作用
【发布时间】:2020-06-26 08:48:35
【问题描述】:

所以我正在整理我的小型 Spring 项目,但由于某种原因,我注意到 @OneToOne 注释没有为我完成它的工作,这反过来又导致另一个模型出现问题。

github 链接:https://github.com/eamonmckelvey/sports-app

基本上,我有一个用户模型类、一个团队模型类和一个玩家模型类。 我希望只有一个用户能够创建一个团队,而一个团队可以拥有许多玩家。 但是,我可以根据需要向我的用户添加任意​​数量的团队,这是错误的。

提供的所有答案都要求我为我的用户类添加一个无参数构造函数和一个构造函数,但是当我这样做时,我从类中注册时出错。

请帮忙。

1。用户模型

 @Entity
 @Data
 @NoArgsConstructor(access= AccessLevel.PRIVATE, force=true)
 @RequiredArgsConstructor
 public class User implements UserDetails {

    @OneToOne(cascade = CascadeType.ALL,mappedBy = "user")
    private Team team;

    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy= GenerationType.AUTO)
    private Long id;
    private final String username;
    private final String password;
    //private final String fullname;




    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"));
    }
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }
    @Override
    public boolean isEnabled() {
        return true;
       }
   }

2。团队模型

@Data
@Entity
 @Table(name="User_Team")

public class Team implements Serializable {

@OneToOne(fetch= FetchType.LAZY)

private User user;

private static final long serialVersionUID = 1L;

@Id
@GeneratedValue(strategy= GenerationType.AUTO)
private Long id;

//@NotBlank(message="Team Name is required")
private  String teamName;

//@NotBlank(message="Location is required")
private  String location;

//@NotBlank(message="Nickname required")
private String nickName;

private String yearEstablished;

public Sport sport;

private Divison divison;

3。团队控制器

@Slf4j
@Controller
@SessionAttributes("Team")

public class TeamController {

private TeamRepository teamRepository;

public TeamController(TeamRepository teamRepository) {
    this.teamRepository = teamRepository;
}

 @Autowired
 TeamRepository service;

 @GetMapping("/team")
 public String displayTeam(Model model) {

    model.addAttribute("team", service.findAll());

    return "/team";
   }

    @GetMapping("/addTeam")
    public String showSignUpForm(User user) {
    return "addTeam";
   }

    @PostMapping("/addTeam")
    public String processOrder(@Valid Team team, BindingResult result, SessionStatus 
    sessionStatus,
                           @AuthenticationPrincipal User user, Model model) {
    if (result.hasErrors()) {
        return "addTeam";
    }

    team.setUser(user);
    service.save(team);
    model.addAttribute("team", service.findAll());
    return "team";
}

4。登记表

@Data
public class RegistrationForm {
private String username;
private String password;
//private String fullname;


 public User toUser(PasswordEncoder passwordEncoder) {
    return new User(
            username, passwordEncoder.encode(password));
}
}

5。注册控制器

@Controller
@RequestMapping("/register")
public class RegistrationController {

private UserRepository userRepo;
private PasswordEncoder passwordEncoder;

public RegistrationController( UserRepository userRepo, 
 PasswordEncoder passwordEncoder){
    this.userRepo = userRepo;
    this.passwordEncoder = passwordEncoder;
}

 @GetMapping
 public String registerForm(){
    return "registration";
 }
  @PostMapping
 public String processRegistration(RegistrationForm form){
    userRepo.save(form.toUser(passwordEncoder));
    return "redirect:/login";
}

6。用户详情类

@Service
public class UserRepositoryUserDetailsService implements 
UserDetailsService {

private UserRepository userRepo;
@Autowired
public UserRepositoryUserDetailsService(UserRepository userRepo) {
    this.userRepo = userRepo;
}
@Override
public UserDetails loadUserByUsername(String username) throws 
UsernameNotFoundException {
    User user = userRepo.findByUsername(username);

    if (user != null) {
        return user;
    }
    throw new UsernameNotFoundException(
            "User '" + username + "' not found");
}

【问题讨论】:

    标签: java sql spring spring-data-jpa hibernate-mapping


    【解决方案1】:

    1) 一个用户可以拥有一个团队。这意味着OneToOne 用户和团队之间的关系。您无需使用 @OneToOne 注释用户和团队。从团队模型中删除 @OneToOne 注释。 所需的更改是:

    用户模型:

    @Entity
    class User{ 
    
        @Id
        private String id;
    
        @OneToOne(fetch = FetchType.LAZY,cascade = CascadeType.ALL)
        @JoinColumn(name = "team_id")
        private Team team;
    
    //other fields
    }
    

    团队模型:

    @Entity
    class Team{
    
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private int id;
        private  String teamName;
        //other field
        }
    

    2) 一支球队有很多球员需要@OneToMany

    【讨论】:

    • 还是不行。它给出了“对于列“用户”的数据太长”。同样在我的团队模型中,我需要一个作为私人用户用户的字段,因为在团队控制器中,我有一个用于添加团队的 @PostMapping 方法。如果我删除私​​人用户用户,此方法会在 team.setUser(user) 处引发错误
    • 你说用户和模型都需要注释,但你说从团队模型中删除注释,这有什么意义?
    【解决方案2】:

    所以,我复制了您的代码并进行了一些更改。进行以下更改后,您的代码可以正常工作。

    1) 从用户类下面的字段中删除 final 关键字(初始化它们似乎不是一个好主意)。

        private final String username;
        private final String password;
    

    2) 用户和团队不应该有相同的序列化版本。

    private static final long serialVersionUID = 1L;
    

    3) 进行上述修正后。您的代码将为您提供实际错误“嵌套异常是 javax.persistence.PersistenceException”

        org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.class]: Invocation of init method failed; nested exception is javax.persistence.PersistenceException: [PersistenceUnit: default] Unable to build Hibernate SessionFactory
            at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1628)
            at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555)
    
    ..............
    ..........
    
        Caused by: org.postgresql.util.PSQLException: ERROR: syntax error at or near "user"
    

    为避免这种情况,请在您的模型中进行以下更改:

    将@Table(name="users") 放入用户模型中。

    以下是模型:

    @Entity
    @Table(name="users")
    public class User {
    
        @Id
        @GeneratedValue(strategy= GenerationType.AUTO)
        private Long id;
        private String username;
        @OneToOne(mappedBy = "user")
        private Team team;
    
        public User() {
        }
    
    }
    

    团队模型

    @Table(name="teams")
    public class Team {
    
    
        @Id
        private Long id;
    
        @OneToOne
        @MapsId
    // or you can use
    //    @OneToOne
    //    @JoinColumn(name="user_id")
        private User user;
    
        private  String teamName;
    
        public Team() {
        }
    
    }
    

    按照上面的代码。这对我来说可以。测试控制器检查:

     @RequestMapping(value = "/test", method = RequestMethod.GET)
        public ResponseEntity<?> test() {
            User user = userRepository.findById(2l);
            Team team = user.getTeam();
            return new ResponseEntity(team, HttpStatus.OK);
    
        }
    }
    

    希望对你有所帮助。

    【讨论】:

    • 嘿,谢谢,你的解决方案是有道理的,但是当我运行它时,我得到这个错误:错误:(18, 5) java: constructor User() is already defined in class sportsapp.sportsapp.User跨度>
    • 为什么我需要一个空的 Public User() 构造函数?
    • 您的解决方案删除了​​ RequiredArgsConstructor 和 NoArgeConstructor 但我正在创建的项目需要它们用于我的注册模型。有解决办法吗?
    • 解决方案不起作用。你还有什么建议吗?谢谢
    【解决方案3】:

    您的代码有几个问题:

    1. 缺少孩子一侧的@JoinColumn。它甚至不在父母一方。在User 实体中声明了@OneToOne(cascade = CascadeType.ALL,mappedBy = "user"),但它没有映射到子类中。
    2. FetchType.LAZY 在一对一的性能方面并没有给你太多,因为 hibernate 需要检查数据库中是否存在对象以知道是返回代理还是 null
    3. 您在TeamControllerservice.save(team); 中保存了一个子实体,但没有从TeamUser 的级联。

    尝试以下映射:

    public class User implements UserDetails {
    
        @OneToOne(cascade = CascadeType.ALL, mappedBy = "user")
        private Team team;
    
        // other fields
    }
    
    public class Team implements Serializable {
    
        @OneToOne(cascade=CascadeType.ALL)
        @JoinColumn(name = "user_id")
        private User user;
    
        // other fields
    }
    

    并保持双方同步。而不是:

    team.setUser(user);
    service.save(team);
    

    在您的TeamController 中尝试以下代码(您必须自动连接UserRepository):

    team = service.save(team);
    team.setUser(user);
    user.setTeam(team);
    userRepository.save(user);
    

    【讨论】:

    • 我得到这个错误:错误:(16、17)java:找不到符号符号:方法值()位置:@interface javax.persistence.JoinColumn,它告诉我使用@JoinColumn(columnDefintion ="user_id"),如果我使用它并运行我得到这个错误:分离的实体传递给持久
    • @EamonMac 抱歉,您需要在@JoinColumn 中添加name = 。我忘记了
    • 好的,完成了,当我保存我的“团队”时,我得到了这个错误:分离的实体传递给坚持。不知道这意味着什么!
    • @EamonMac 你能在service.save(team); 之前添加user.setTeam(team); 然后再试一次吗?
    • 当我这样做时,我得到了我原来的问题..外键有效,但保存了多个实例。:(
    【解决方案4】:

    嘿,所以我在这里找到了我的代码的修复程序。

    1。团队控制器

          @GetMapping("/addTeam")
          public String showSignUpForm(SessionStatus sessionStatus,
                                 @AuthenticationPrincipal User user, Model model) 
     {
          //if the user has already the team we should not let them add another 
          // one
          //this is due to having one to one relationship
         long userHasTeamCount = service.countAllByUser(user);
         if (userHasTeamCount > 0) {
    
            return "redirect:team";
    
         }
    
        return "addTeam";
      }
    

    2。团队模式

       @OneToOne(fetch = FetchType.EAGER)
       @JoinColumn(name = "user_id", referencedColumnName = "id")
       private User user;
    

    3。用户模型

    这里删除了不需要的 OneToOne

    4。团队回购

    @Repository
    public interface TeamRepository extends JpaRepository<Team, Long> {
    Team findAllById(Long id);
    
    
    long countAllByUser(final User user);
    

    }

    【讨论】:

    • 一个团队可以有很多用户吗?如果是这样,我认为您的 Team.user 字段应该是带有 @OneToMany 注释的集合(命名用户),因为 One 团队可以拥有 Many 用户另外,我认为您的 TeamRepository。 findAllById 最好命名为 findById
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-24
    • 2014-03-12
    • 2018-07-09
    • 1970-01-01
    • 2013-10-13
    相关资源
    最近更新 更多