【问题标题】:Unidirectional @OneToOne resulting in null foreign key单向 @OneToOne 导致空外键
【发布时间】:2020-05-09 20:18:15
【问题描述】:

我有两个实体:

User.java

@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class User implements UserDetails {
    @Id
    @GeneratedValue
    Long id;

    @NotBlank
    String username;
    @NotBlank
    String password;

    @ElementCollection
    @Builder.Default
    List<String> roles = new ArrayList<>();

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return this.roles.stream().map(SimpleGrantedAuthority::new).collect(toList());
    }

    @Override
    public String getUsername() {
        return username;
    }

    @Override
    public boolean isAccountNonExpired() {
        return false;
    }

    @Override
    public boolean isAccountNonLocked() {
        return false;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return false;
    }

    @Override
    public boolean isEnabled() {
        return false;
    }
}

Student.java

@Entity
@Data
public class Student {
    @Id
    String id;
    String name;
    String firstName;

    @OneToOne
    @JoinColumn(name = "user_id")
    User user;

    public void addUser(User user) {
        this.user = user;
    }
}

StudentService 应该添加一个新的Student,创建一个新的User 并将其添加到Student

@Override
public boolean addStudent(StudentDTO student) {
    if (!studentRepository.existsById(student.getId())) {
        Student s = modelMapper.map(student, Student.class);
        studentRepository.save(s);

        String username = String.format("s%s", student.getId());
        List<String> roles = Arrays.asList("ROLE_STUDENT");
        User user = userService.createUser(username, roles);
        userService.addUser(user);
        s.addUser(user);

        return true;
    }
    return false;
}

UserUserService 创建

@Override
public User createUser(String username, List<String> roles) {
    String password = RandomStringUtils.randomAlphanumeric(16);
    User u = User.builder()
            .username(username)
            .password(encoder.encode(password))
            .roles(roles)
            .build();
    if (addUser(u)) {
        return u;
    } else {
        throw new UserAlreadyExistingException(username);
    }
}

@Override
public boolean addUser(User user) {
    boolean alreadyExists = userRepository.findByUsername(user.getUsername()).isPresent();
    if (true) {
        userRepository.save(user);
        return true;
    }
    return false;
}

尽管UserStudent 已添加到我的数据库中,student 表中的user_id 列始终设置为空。我还检查了添加到StudentUser 是否已正确初始化并填充了所有信息,但事务已提交。

【问题讨论】:

    标签: spring hibernate entity relationship one-to-one


    【解决方案1】:

    user_id 设置为 null,因为您没有将映射保存到数据库。 使用 cmets 更改代码:

    @Override
    public boolean addStudent(StudentDTO student) {
        if (!studentRepository.existsById(student.getId())) {
            Student s = modelMapper.map(student, Student.class);
         // don't save student here
    
            String username = String.format("s%s", student.getId());
            List<String> roles = Arrays.asList("ROLE_STUDENT");
            User user = userService.createUser(username, roles);
            userService.addUser(user);
            s.addUser(user);
            //save student here after adding user. 
            studentRepository.save(s)
            return true;
        }
        return false;
    }
    

    【讨论】:

    • 是的,就是这样,但是如果我在Student 类的@OneToOne 注释中添加cascade = CascadeType.ALL,当我尝试添加一个新学生时,它会抛出一个java.lang.UnsupportedOperationException,为什么?
    • 对于java.lang.UnsupportedOperationException,看看这个 - stackoverflow.com/a/7428143/7505731
    • Arrays.asList() 不是我猜的 curlprit,我试图在Student 之前不保存User,所以User 被添加到Student 然后他们都将保存在一个事务中。在这种情况下,cascade = CascadeType.ALL 似乎可以工作。你知道为什么吗?
    • 无法弄清楚。它有效还是仍然是一个问题?
    • 我通过将UserStudent 添加到一个事务中来解决。
    猜你喜欢
    • 1970-01-01
    • 2013-10-12
    • 2019-04-16
    • 2015-08-24
    • 2012-09-28
    • 1970-01-01
    • 1970-01-01
    • 2016-05-26
    • 2021-10-20
    相关资源
    最近更新 更多