Spring Boot数据JPA双向关系-外键为空

问题描述 投票:0回答:1

我一直在做关于英雄和恶棍的侧面 spring-boot 演示项目。下面是由 SuperheroVillain 类扩展的 Character 类:

@Data
@NoArgsConstructor
@Entity
@Table(name = "characters")
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes({
        @JsonSubTypes.Type(value = Superhero.class, name = "superhero"),
        @JsonSubTypes.Type(value = Villain.class, name = "villain")})
public abstract class Character {
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    private Integer id;
    private String firstName;
    private String lastName;
    @Transient
    private String fullName;
    @Convert(converter = GenderConverter.class)
    private Gender gender;
    @Column(nullable = false)
    private String alias;
    @Convert(converter = StatusConverter.class)
    private Status status;
    @ManyToOne
    @JoinColumn(name = "team_id")
    private Team team;
    private String originStory;
    @Convert(converter = UniverseConverter.class)
    private Universe universe;

    public Character(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public Character(String firstName, String lastName, String alias) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.alias = alias;
    }

    public String getFullName() {
        return firstName + " " + lastName;
    }
}

然后是团队,可以由多个英雄或恶棍组成,尽管一名英雄或恶棍只能与一个团队相关联:

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "teams")
public class Team {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String name;
    @OneToMany(mappedBy = "team", cascade = CascadeType.ALL)
    private List<Character> characters;
    @Convert(converter = StatusConverter.class)
    private Status status;
}

这是我尝试初始化以及存储库中的那些实体的方式:

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    /** Disable before running Tests! */
    @Bean
    public CommandLineRunner commandLineRunner(CharacterRepository characterRepository,
                                               TeamRepository teamRepository) {
        return args -> {
            // Initilaizing
            Superhero ironMan = new Superhero("Tony", "Stark", "Iron Man");
            Superhero thor = new Superhero("Thor", "Odinson", "God of Thunder");
            Team avengers = Team.builder().name("Avengers").status(DISBANDED).build();

            // Setting attributes
            ironMan.setGender(MALE); thor.setGender(MALE);
            ironMan.setUniverse(MCU); thor.setUniverse(MCU);
            ironMan.setStatus(DECEASED); thor.setStatus(ALIVE);

            // Saving to repositories
            characterRepository.saveAll(List.of(ironMan, thor));
            teamRepository.save(avengers);

            // Trying to assign foreign keys
            avengers.setCharacters(List.of(ironMan, thor));
            ironMan.setTeam(avengers);
            thor.setTeam(avengers);
        };
    }
}

postgres 中的结果如下所示:

demo2=# SELECT * FROM teams;
 id |   name   |  status
----+----------+-----------
  1 | Avengers | Disbanded
(1 row)


demo2=# SELECT * FROM superheroes;
 id | team_id |     alias      | first_name | gender | last_name | origin_story |  status  | universe
----+---------+----------------+------------+--------+-----------+--------------+----------+----------
  1 |         | Iron Man       | Tony       | Male   | Stark     |              | Deceased | MCU
  2 |         | God of Thunder | Thor       | Male   | Odinson   |              | Alive    | MCU
(2 rows)

正如您所见,两个英雄的外键

team_id
都是空的。我尝试在
referencedColumnName
注释中添加
JoinColumn
,添加级联类型,获取数据,然后设置设置属性,但都没有帮助。

java spring postgresql spring-boot spring-data-jpa
1个回答
0
投票

我经常发现在双向 @OneToMany 和 @ManyToOne 关系中使用辅助方法很有用。例如,在团队实体中,我将添加以下实体:

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "teams")
public class Team {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String name;
    @OneToMany(mappedBy = "team", cascade = CascadeType.ALL)
    private List<Character> characters;
    @Convert(converter = StatusConverter.class)
    private Status status;

    // Helper Method
    public void addCharacter(Character character){
      characters.add(character);
      character.setTeam(this);
    }
   // You can have a similar method for adding many characters at once
}

然后更改命令行运行程序如下:

@Bean
    public CommandLineRunner commandLineRunner(CharacterRepository characterRepository,
                                               TeamRepository teamRepository) {
        return args -> {
            // Initilaizing
            Superhero ironMan = new Superhero("Tony", "Stark", "Iron Man");
            Superhero thor = new Superhero("Thor", "Odinson", "God of Thunder");
            Team avengers = Team.builder().name("Avengers").status(DISBANDED).build();

            // Setting attributes
            ironMan.setGender(MALE); thor.setGender(MALE);
            ironMan.setUniverse(MCU); thor.setUniverse(MCU);
            ironMan.setStatus(DECEASED); thor.setStatus(ALIVE);

            // Saving to repositories
            characterRepository.saveAll(List.of(ironMan, thor));
            

            // Trying to assign foreign keys
            avengers.addCharacter(ironMan);
            avengers.addCharacter(thor);
            teamRepository.save(avengers);
        };
    }
© www.soinside.com 2019 - 2024. All rights reserved.