Need help with setting up table relationships. So, there are 2 entities – Section and Period. 1 Section has many Period, but 1 Period do not belongs to any specific Section. I implemented this relationship as follows: created an additional table SectionCodes with an external key on Section (more in diagram)
Section class:
@Entity @Table(name = "section") @AttributeOverride(name = "id", column = @Column(name = "id", nullable = false)) public class Section extends BaseEntity<Integer> { private String form; private Integer version; private List<SectionPeriod> periodCodes; @Column(name = "form") public String getForm() { return form; } public void setForm(String form) { this.form = form;} @Column(name = "version") public Integer version() { return version; } public void setVersion(Integer version) { this.version = version; } @OneToMany(mappedBy = "section", fetch = FetchType.LAZY, cascade = CascadeType.ALL) public List<SectionPeriod> getPeriodCodes() { return periodCodes; } public void setPeriodCodes(List<SectionPeriod> periodCodes) { this.periodCodes = periodCodes; } }
SectionPeriod:
@Entity @Table(name="section_period") @AttributeOverride(name = "id", column = @Column(name = "id", nullable = false)) public class SectionPeriod extends BaseEntity<Integer> { private Integer periodCode; private Section section; @Column(name = "period_code") public Integer getPeriodCode() { return periodCode; } public void setPeriodCode(Integer periodCode) { this.periodCode = periodCode; } @ManyToOne() @JoinColumn(name = "section_id", referencedColumnName = "id", nullable=false) public Section getSection () { return section; } public void setSection(Section section) { this.section = section; } }
This works fine, but there is a problem – it turns out that every Section entity has a SectionPeriod list, and SectionPerid has a Section – so there is loop. Is there an easy way to perform this? Ideally, it should be just List of Period in Section class or at least Integer[] of periodCodes.
Advertisement
Answer
To model the Many To Many relationship between Period and Section, you have 2 choices:
- Use 2 Entities (Period, Section), and use the @ManyToMany annotation in one of these entities. This will autogenerate the Join Table which will have a composite primary key. This is not recommended.
- Use 3 Entities, and this way you can think the “ManyToMany” as having two OneToMany relationships (1 Period – Many “PeriodSection” AND 1 Section – Many “PeriodSection”). This is recommended because this way you will have a PK and you can easily add more columns to the PeriodSection (** Note: instead of PeriodSection, the Entity and Table should have a meaninful name, but i’ll leave that to you)
Using the second choice:
Period:
@Entity @Table(name = "periods") public class Period { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private Integer code; private String name; @OneToMany(mappedBy = "period", cascade = CascadeType.MERGE, fetch = FetchType.LAZY) private List<PeriodSection> periodSections; // bad naming. }
PeriodSection:
@Entity @Table(name = "period_section") // use a more meaningful name for the table and the entity public class PeriodSection { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @ManyToOne(cascade = CascadeType.MERGE) @JoinColumn(name = "period_id", referencedColumnName = "id") private Period period; @ManyToOne(cascade = CascadeType.MERGE) @JoinColumn(name = "section_id", referencedColumnName = "id") private Section section; }
Section:
@Entity @Table(name = "sections") public class Section { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private Integer version; private String form; @OneToMany(mappedBy = "section", cascade = CascadeType.MERGE, fetch = FetchType.LAZY) private List<PeriodSection> periodSections; // bad naming. }
You can play around with the fetch and cascade strategies, to check which is best for your app. Hope this helped