Картография @OneToOne не работает в моем проекте Java Spring - PullRequest
3 голосов
/ 14 марта 2020

Итак, я убираю свой маленький проект Spring и по какой-то причине заметил, что аннотация @OneToOne не выполняет для меня свою работу, что, в свою очередь, вызывает проблемы в другой модели.

ссылка на github: https://github.com/eamonmckelvey/sports-app

По сути, у меня есть класс модели User, класс модели команды и класс модели игрока. Я хочу, чтобы только один пользователь мог создать одну команду, а одна команда должна иметь много игроков. Тем не менее, я могу добавить столько команд своему пользователю, сколько захочу, что неверно.

Все ответы требуют от меня добавления конструктора no arg и конструктора для моего класса пользователей, но когда я это делаю это я получаю сообщение об ошибке при регистрации в классе.

Пожалуйста, помогите.

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

Ответы [ 4 ]

5 голосов
/ 14 марта 2020

Итак, я скопировал ваш код и сделал некоторые изменения. После следующих изменений ваш код работает нормально.

1) Удалить последнее ключевое слово из полей ниже в пользовательском классе (инициализация их не кажется хорошей идеей).

    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"

Чтобы избежать этого, сделайте следующие изменения в вашей модели:

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

    }
}

Надеюсь, это вам поможет.

4 голосов
/ 14 марта 2020

1) Один пользователь может иметь одну команду. Это означает OneToOne отношение между пользователем и командой. Вам не нужно аннотировать как пользователя, так и команду с помощью @ OneToOne.Remove @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

2 голосов
/ 20 марта 2020

Эй, я нашел исправление для своего кода.

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

}

2 голосов
/ 17 марта 2020

Есть несколько проблем с вашим кодом:

  1. @JoinColumn на дочерней стороне отсутствует. Это даже не на родительской стороне. В сущности User вы объявляете @OneToOne(cascade = CascadeType.ALL,mappedBy = "user"), но она не отображается в дочернем классе.
  2. FetchType.LAZY не дает вам много в плане производительности один-к-одному, так как потребности в спящем режиме чтобы проверить базу данных на предмет наличия объекта, узнать, возвращаете ли вы прокси или null.
  3. Вы сохраняете дочернюю сущность в вашем TeamController: service.save(team);, но нет каскадирования из Team до User.

Попробуйте следующее сопоставление:

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);
...