0

I'm new in Spring Boot JPA

I have questions in JPA Entity mappings.

there is 4 tables in my MySql DB

SPACE, PROJECT, ISSUE, MEMBER

SPACE is Big Project which contains multiple PROJECT.

PROJECT contains multiple ISSUE.

and MEMBER can join only 1 SPACE and multiple PROJECT which MEMBER belongs to SPACE. MEMBER can write multiple ISSUE

in this situation, my ERD model is correct?

my ERD

and please check my jpa mappings. If there's anything wrong, please point it out.

    SPACE

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "space_no")
    private Long spaceNo;

    @NotEmpty
    @Column(name = "space_name", unique=true, length = 100)
    private String spaceName;

    /** 1:N relation */
    @OneToMany(mappedBy = "smsSpace")
    private List<PmsProject> pmsProjects = new ArrayList<>();

    PROJECT
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "project_no")
    private Long projectNo;

    @Column(name ="space_no")
    private Long spaceNo;

    @Column(name = "project_name", length = 100)
    private String projectName;

    /** 1:N relation */
    @OneToMany(mappedBy = "pmsProject")
    private List<ImsIssue> imsIssues = new ArrayList<>();

    @OneToMany(mappedBy = "pmsProject")
    private List<PmsProjectMember> projectMembers = new ArrayList<>();

    /** N:1 relation */
    @ManyToOne
    @JoinColumn(name = "space_no", referencedColumnName = "space_no", insertable = false, updatable = false)
    private SmsSpace smsSpace;
MEMBER

  @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "member_no")
    private Long memberNo;

    @Column(name = "mail_address", unique=true, length = 100)
    private String mailAddress;

    @Column(name = "name", length = 100)
    private String name;

    @Column(name = "keyword", length = 1000)
    private String keyword;

    @Column(name = "image", length = 1000)
    private String image;

    @Column(name = "password", length = 1000)
    private String password;

    @Column(name = "user_id", length = 50)
    private String userId;

    @Enumerated(EnumType.STRING)
    private MemberRole role;

    public void encodingPassword(String password) {
        this.password = password;
    }

    /** 1:N realtion */
    @OneToMany(mappedBy = "mmsMember")
    private List<PmsProjectMember> projectMembers = new ArrayList<>();
ISSUE
 @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "issue_no")
    private Long issueNo;

    @Column(name ="project_no")
    private Long projectNo;

    @Column(name = "issue_name", length = 1000)
    private String issueName;

    @Column(name = "priority")
    private Long priority;

    @Column(name = "status", length = 20)
    private String status;

    @Column(name = "summary", length = 100)
    private String summary;

    @Column(name = "is_overdue")
    private Long isOverdue;

    @Column(name = "issue_type_cd")
    private String issueTypeCd;

    /** N:1 relation */
    @ManyToOne
    @JoinColumn(name = "project_no", referencedColumnName = "project_no", insertable = false, updatable = false)
    private PmsProject pmsProject;
PROJECTMEMBER

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "group_no")
private Long groupNo;

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "member_no")
private MmsMember mmsMember;

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "project_no")
private PmsProject pmsProject;

I've been thinking about it for days, but I can't solve it because I lack knowledge. Please help me.

Doo9104
  • 43
  • 1
  • 8
  • Let me ask you something before I answer, are you new with databases in general? – xTheDoctah Aug 13 '21 at 08:15
  • @A.Caldarigi I am almost new. why? – Doo9104 Aug 13 '21 at 08:32
  • About the ERD: Why there's a Member_no in your **project** table? What is used for ? In your **issue** table there's a Member_no, that one should be a Fk.(you want just an user to be in that issue?) Shouldnt you take note which use is in which space ? – xTheDoctah Aug 13 '21 at 09:10
  • @A.Caldarigi Thank you so much for your answer. I revised it as you said. I added PROJECTMEMBER JPA mapping. PROJECT M : N MEMBER. is there a problem in JPA entity mapping? – Doo9104 Aug 13 '21 at 10:32
  • In the JPA entities there are various errors: First are all manytomany relationship, do not need any extra Entity, you map an extra field on each entity with @ManyToMany annotation, more info can be found here https://www.baeldung.com/jpa-many-to-many – xTheDoctah Aug 13 '21 at 11:22

1 Answers1

0

Assuming I got your situation right, you have A member that can have one Space and multiple project, space has multiple projects, every project can have more than one issue, every member can write more then one issue for each project.

Due to the suggestion the ERD you posted it's not corrected.

Here is the correct ERD

(I just wrote the Foreign Keys and Primary Keys, the rest its up to you)

enter image description here

And here you have all the entites:

Member

@Entity
@Table(name = "MEMBERS")
public class Member {

    //members is the property name in Project entity.
    @ManyToMany(mappedBy = "members")
    Set<Project> projects;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY, generator = "native")
    @Column(name = "MEMBER_ID")
    private Long id;
    @ManyToOne
    @JoinColumn(name = "SPACE_ID")
    private Space space;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Space getSpace() {
        return space;
    }

    public void setSpace(Space space) {
        this.space = space;
    }

    public Set<Project> getProjects() {
        return projects;
    }

    public void setProjects(Set<Project> projects) {
        this.projects = projects;
    }
}

Space

@Entity
@Table(name = "SPACES")
public class Space {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY, generator = "native")
    @Column(name = "SPACE_ID")
    private Long id;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }
}

Issue

@Entity
@Table(name = "ISSUES")
public class Issue {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY, generator = "native")
    @Column(name = "ISSUE_ID")
    private Long id;

    @ManyToOne
    @JoinColumn(name = "MEMBER_ID")
    private Member member;


    @ManyToOne
    @JoinColumn(name = "PROJECt_ID")
    private Project project;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Member getMember() {
        return member;
    }

    public void setMember(Member member) {
        this.member = member;
    }

    public Project getProject() {
        return project;
    }

    public void setProject(Project project) {
        this.project = project;
    }
}

Project

@Entity
@Table(name = "PROJECTS")
public class Project {
    @ManyToMany
    @JoinTable(
            name = "PROJECTS_MEMBERS",
            joinColumns = @JoinColumn(name = "PROJECT_ID"),
            inverseJoinColumns = @JoinColumn(name = "MEMBER_ID"))//Is referring to the id of the other Entity, in this case, members
    Set<Member> members;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY, generator = "native")
    @Column(name = "PROJECT_ID")
    private Long id;
    @ManyToOne
    @JoinColumn(name = "SPACE_ID")
    private Space space;

    public Set<Member> getMembers() {
        return members;
    }

    public void setMembers(Set<Member> members) {
        this.members = members;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Space getSpace() {
        return space;
    }

    public void setSpace(Space space) {
        this.space = space;
    }


}

You don't have to put necessarily both @ManyToOne and @OneToMany annotation, the back-reference could be useful in some use case, you have to see if you need it or not. Remember the back reference could cause problems with deserialization, creating a stack overflow by circular reference. You can avoid this, using transient keyword or various annotation (depending on the library you are using, Jackson, Gson, ecc..).

Be careful to don't use FetchType.EAGER randomly here's the why => Difference between FetchType LAZY and EAGER in Java Persistence API?

xTheDoctah
  • 276
  • 1
  • 11
  • Thank you very much for your kind and detailed reply. I'll study and analyze the answers you posted. If you have any questions, I'll ask you in the comments. Thank you so much! – Doo9104 Aug 13 '21 at 17:14
  • If i only know the member's email information, how can i get the space and project that the member belongs to? Should I use the method to obtain MmsMember from the memberRepository by email, find out the spaceNo of MmsMember, and then look up the project that has spaceNo? I am currently experiencing an Infinite recovery error in the project and member. – Doo9104 Aug 14 '21 at 14:14
  • You can do that or use a native query with Join. A personal suggestion, try to achieve this result just using a query, then try with the Repository – xTheDoctah Aug 14 '21 at 14:20
  • By the way in theory you can just do a customMethod into the repository something like `findByEmail(String email)` and then take from the given object the projects and space params – xTheDoctah Aug 14 '21 at 14:32
  • Oh, I was a fool. If i just use findByEmail method, smsSpace and pmsProject are included inside. But what's the problem of getting only one project? The ProjectMember table stores three projects. [link](https://imgur.com/segOav0) [link](https://imgur.com/kCd6SrM) these are debugging and DB capture – Doo9104 Aug 14 '21 at 15:22
  • are all those 3 projects related to the user you were looking for ? – xTheDoctah Aug 14 '21 at 16:42
  • yes. [database](https://imgur.com/ULR6jHo) 3 projects are in 1 space, and member have spaceNo – Doo9104 Aug 14 '21 at 17:14
  • @Doo9104 what was the problem? – xTheDoctah Aug 15 '21 at 13:30
  • I don't know exactly why, but I converted ManyToMany to OneToMany and ManyToOne, and promoted the ProjectMember table to entity. Since then, the problem has been resolved. There is a possibility that additional columns will be included in the ProjectMember table later. – Doo9104 Aug 15 '21 at 14:21
  • I searched Google all night for the cause, but I couldn't even figure out the cause. :( – Doo9104 Aug 15 '21 at 14:22