Spring\JPA\PostgreSQL: Why do I get a table I didn't create?

Viewed 371

I am building a spring boot for the first time. I am using Spring boot version 2.3.4. I also use PostgreSQL. I wanted to create two tables: Player and Team. The team should have a list of players.

So I created the next two Entity classes:

@Entity
@Table(name = "Players")
public class Player {
    
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name="player_id")
    private Long playerId;
    
    private String name;
    
    private int dateOfBirth;
    
    private String originCountry;
    
    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "team_id", referencedColumnName = "team_id")
    private Team team;
}

and

@Entity
@Table(name = "Teams")
public class Team{

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name="team_id")
    private Long teamId;
    
    private String name;
    
    private String country;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "team", orphanRemoval = true)
    private List<Player> players = new ArrayList();

}

As you probably already know, spring boot created the tables automatically. The problem that the Team table doesn't have the players column\s.

What is wrong here? Maybe I don't need to see the players columns in the Team table? (which seems strange to me...) Is there a better way to define a list or array of values?

Also, I want to understand: does @JoinColumn(name="team_id")) defined the column name of Player's team property private Team team;?

Thanks!!

1 Answers

I think you are confusing two different concepts when you think about object-relational mapping (ORM). Remember you are using JPA and, behind the scenes, Hibernate. One thing is your objects for the Java application, another is the set of tables you have, for example, think about a Many to Many relation alone. You can map it easily with 2 objects:

class Match {
...
    private Set<Team> teams;
...
}

class Team {
...
    private Set<Match> matches;
...
}

That's a many-to-many composition of two objects. But how can you map it on a normalized relational database? You need a Junction Table in this case, so you will have the two tables plus a team_match table which will have only the id of a team and the id of a match and both fields will be a unique constraint. Therefore, when you want to fetch the information you will use a JOIN, like this:

SELECT t.*, m.* FROM team t
  JOIN team_match tm ON t.id = tm.team_id
  JOIN match m ON m.id = tm.match_id

What happen is that the framework, in this case Hibernate, abstracts all of this translating the objects into tables. And, sometimes, it will not be one object to one table exactly.

With that in mind, thinking about relational databases, you will always need that extra table. You can achieve that in Postgres using a jsonb type, but I would not recommend in this case, so I will not write more about it. Nevertheless, I recommend you to dive deeper reading about ORM (object-relational mapping) to understand better what will happen behind the scenes. And hope the answer helps you.

EDIT:

Ok, sorry, your comment made me realize that I could show you the way to achieve that. So, the most canonical way of doing that would be something like this:

@Entity
class Team
{
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name="team_id")
    private Long teamId;

    // ...
    @OneToMany(mappedBy = "team", fetch = LAZY, cascade = ALL)
    private List<PlayerId> players;
    // ...
}

@Entity
class PlayerId {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name="player_id")
    private Long playerId;

    @ManyToOne(fetch = LAZY)
    @JoinColumn(name = "team_id", referencedColumnName = "team_id")
    private Team team;
    // ...
}

Note that the @OneToMany annotation references the object composed in the target entity. Hope it helps.

EDIT 2:

About the @JoinColumn: the name is the join column in the current table/entity and the referencedColumnName is the join column in the foreign table/entity.

Related