Foreign Keys in Spring Boot (MySQL, Hibernate, JPA) - mysql

I am trying to write a RESTful API using Spring Boot and I am not able to figure out a way to map my relations in the database. I have a User and a Reports table. Each User can have multiple Reports, and a single report consists of "FROM USER" and "TO USER" columns to indicate who sent the report and to whom. My User ID is the primary key and for the Report table, I am generating REPORT ID as the primary key using AUTO INCREMENT. Here is my User model class -
#Entity
#Table (name = "user")
#EntityListeners(AuditingEntityListener.class)
public class User {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String firstName;
private String lastName;
private String email;
private String password;
#OneToMany(mappedBy = "user",cascade = CascadeType.ALL)
private List<Report> reportReceivedList;
#OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
private List<Report> reportSentList;
/* Getters and setters ..... */
}
Here is my Report Model class -
#Entity
#Table (name = "report")
#EntityListeners(AuditingEntityListener.class)
public class Report {
#Id
#Column (name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne()
#JoinColumn(name = "from_user_id")
private Long fromUserId; //THIS SHOULD BE FROM "USER" TABLE
#ManyToOne()
#JoinColumn(referencedColumnName = "to_user_id")
private Long toUserId; //THIS SHOULD BE FROM "USER" TABLE
#Temporal(TemporalType.DATE)
#CreatedDate
private Date createdAt;
private String observation;
private String context;
//Other variables and getters and setters .....
}
Can someone please show me a way to correctly define this relationship. My current model doesn't work. Also, I want rows from REPORT class to be deleted as soon as a user is deleted. Thanks!

I finally fixed it by changing my User class as follows -
#OneToMany(cascade = CascadeType.ALL, targetEntity = Report.class)
#JoinColumn(name = "to_user_id")
private List<Report> reportReceivedList;
#OneToMany(cascade = CascadeType.ALL, targetEntity = Report.class)
#JoinColumn(name = "from_user_id")
private List<Report> reportSentList;
And by changing my Report class as -
#Column(name = "from_user_id")
private Long fromUserId;
#Column(name = "to_user_id")
private Long toUserId;

Related

Use same Entity multiple times in another Entity

I am implementing a Spring Boot server using JPA and Hibernate where there are 2 entities: Channel and Translation.
The Channel entity has two fields (nameTranslations and descriptionTranslations that should hold the name and description of a channel in 2 languages french and english) which are of type Translation as described as follow:
Class Channel
#Entity
#Table(name = "CHANNEL")
public class Channel {
#Id
#Column(name = "ID")
private String id;
#OneToOne(mappedBy = "channel", cascade = CascadeType.ALL)
private Translation nameTranslations;
#OneToOne(mappedBy = "channel", cascade = CascadeType.ALL)
private Translation descriptionTranslations;
}
and
Class Translation
#Entity()
#Table(name = "TRANSLATION")
public class Translation {
#Id
#Column(name = "ID")
private String id;
#Column(length = 1024)
private String en;
#Column(length = 1024)
private String fr;
}
My issue is: How can I implement the previously described logic so that there are 2 Translation fields in the Channel class? I have tried it so far using #OneToOne annotation, but it doesn't work.
I'm not sure what kind of mapping you are trying to achieve, but this will work:
#Entity
#Table(name = "CHANNEL")
public class Channel {
#Id
#Column(name = "ID")
private String id;
#OneToOne(cascade = CascadeType.ALL)
private Translation nameTranslations;
#OneToOne(cascade = CascadeType.ALL)
private Translation descriptionTranslations;
}
or, if you want the columns on the other entity table:
#Entity
#Table(name = "CHANNEL")
public class Channel {
#Id
#Column(name = "ID")
private String id;
#OneToOne(mapped="name", cascade = CascadeType.ALL)
private Translation nameTranslations;
#OneToOne(mapped="description", cascade = CascadeType.ALL)
private Translation descriptionTranslations;
}
#Entity
#Table(name = "TRANSLATION")
public class Translation {
#Id
#Column(name = "ID")
private String id;
#Column(length = 1024)
private String en;
#Column(length = 1024)
private String fr;
#OneToOne
private Channel name;
#OneToOne
private Channel description;
}
See the Hibernate ORM documentation for one-to-one associations.

Many to many relation ship gives null

using spring data and mysql as persistence layer getting some issues in Many to many mappings
#Getter
#Setter
public class BusinessUnitEntitiy extends AbstractTenantEntity implements Auditable{
private static final long serialVersionUID = -1123383144979037984L;
#Column(name = "NAME")
String name;
#Column(name = "DESCRIPTION")
String description;
#ManyToMany(fetch = FetchType.LAZY,mappedBy = "businessUnits" )
private Set<User> businessUsers;
public Set<User> fetchBusinessUsers() {
return businessUsers;
}
#Column(name = "DISPLAY_SEQUENCE_NUM")
protected Long displaySequenceNum;
#Column(name = "UNIQUE_SEQUENCE_ID",unique = true)
protected String uniqueSequenceId;
}
#Getter
#Setter
public class User extends AbstractTenantEntity {
private static final long serialVersionUID = 65981149772133526L;
#Column(name = "PROVIDER_USER_ID")
private String providerUserId;
private String email;
#Column(name = "enabled", columnDefinition = "BIT", length = 1)
private boolean enabled;
#Column(name = "DISPLAY_NAME")
private String displayName;
private String password;
private String provider;
#Column(name = "DISPLAY_SEQUENCE_NUM")
protected Long displaySequenceNum;
#Column(name = "UNIQUE_SEQUENCE_ID",unique = true)
protected String uniqueSequenceId;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(
name = "business_unit_user",
joinColumns={#JoinColumn(name ="user_id")},
inverseJoinColumns = { #JoinColumn(name="business_unit_id") }
)
Set<BusinessUnitJpaEntitiy> businessUnits;
}
fetching the user from businessunit works perfectly
but fetching businessunits from users gives null set even updating the same user is persisiting only the newly linked businessunit older values vanishes
If you persisted the user within the transaction without initializing the businessUnits fields, that's what you get. Either you also initialize the set correctly before persisting, or you detach the user after persisting, so that the user is reloaded from the database and the set is properly initialized.
you can try this
#ManyToMany
#JoinTable(
name = "business_unit_user",
joinColumns={#JoinColumn(name ="user_id",referencedColumnName = "id")},
inverseJoinColumns = { #JoinColumn(name="business_unit_id",referencedColumnName = "id") }
)
Set<BusinessUnitJpaEntitiy> businessUnits;
and you must have setter and getter for each property

JPA mapping for one-to-many collection of shared data, with user specific values

I have a User model that contains a list of achievements
#Table(name = "user")
#Entity
#NamedEntityGraph(name = "User.achievements",
attributeNodes={
#NamedAttributeNode("achievements")
})
#Data
public class User {
#Id
#NotNull
#Column(name = "username")
private String username;
#Column(name = "password")
private String password;
#ElementCollection(fetch = FetchType.LAZY, targetClass = Achievement.class)
private List<Achievement> achievements = new ArrayList<>();
}
Here's the achievement model
#Entity
#Data
#Table(name = "achievement")
public class Achievement {
#Id
#GeneratedValue(generator = "system-uuid")
#GenericGenerator(name = "system-uuid", strategy = "uuid")
private String achievementId;
#Column(name = "title")
private String title;
#Column(name = "description")
private String description;
#Column(name = "achieved", columnDefinition="BOOLEAN DEFAULT false", nullable = false)
private boolean achieved = false;
user_achievements table generated from #ElementCollection mapping, which atm only contains user and achievement foreign keys
I am looking to move the boolean achieved value to the user_achievements table, ideally without having to create a separate model User_Achievements
I am fairly new to using Jpa, but i feel like this scenario is too basic so there must be a straight forward way to do that i cant seem to locate it
#Entity
class UserAchievement {
#EmbeddableId
UserAchievementId id;
#ManyToOne(fetch=LAZY)
#JoinColumn(name="user_username", insertable=false, updatable=false)
User user;
#ManyToOne(fetch=LAZY)
#JoinColumn(name="achivement_achivement_id", insertable=false, updatable=false)
Achivement achivement;
// and other fields
}
class User {
// ...
#OneToMany(mappedBy="user")
List<UserAchievement> userAchievements;
}
and you need to define UserAchievementId

Advise a dummy on how to structure my query and set up my mapping

Pardon me if this looks too basic, I am just a beginner in springboot. I am trying to create a simple project. I have entity class "company.java" and another "jobs.java"
I have already mapped them such that it will be saving both "companyID,jobID"
now my question is here :
1) how can I ensure that the record is captured into that new table when i feed data from thymeleaf fields. I have tried a dummy entry and its saving jobs into the jobs table but its not capturing anything to insert into the joined table
2) How do I query such that it saves and also when I search a job by its ID it shows me the company.
#Entity
#Table(name = "company_account")
#EntityListeners(AuditingEntityListener.class)
#SecondaryTable(name = "company_profile")
public class CompanyAccount {
private int id;
private String CompanyName;
private String PhoneNumber;
private String Number_of_employees;
private String CompanyURL;
private String OrganisationType;
private String PrimaryIndustry;
private byte[] Logo;
private String Location;
private String DateEstablished;
private String Headquarters;
private String SocialMedia;
public CompanyAccount() {
}
///////////////////////here i tried the mapping
#OneToMany(fetch = FetchType.LAZY, mappedBy = "company_account")
private List<NewJobs> jobs = new ArrayList<NewJobs>();
#Id
// #org.hibernate.annotations.ColumnDefault("001")
#GeneratedValue(strategy = GenerationType.AUTO)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
//////////////////////////////////
deleted the getters and setters
///////////////////////////////////////////////////////////////
#Entity
#Table(name = "newjobs")
#EntityListeners(AuditingEntityListener.class)
public class NewJobs {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#org.hibernate.annotations.ColumnDefault("001")
private int newjobid;
public NewJobs() {
}
tried my mapping here
#ManyToOne(fetch = FetchType.LAZY)
// #JoinColumn(name = "company_account")
#JoinTable(name = "company_jobs", joinColumns = { #JoinColumn(name = "id") }, inverseJoinColumns = {
#JoinColumn(name = "newjobid") })
private CompanyAccount CompanyAccount;
}
How can I query my insert and also my search by id ?

Unable to insert data into link table in hibernate many to many

Relations are like
A project can have many employees.
on a JSP, On selecting a project, all employees are populated.
A text box for task.
Provide a task name for that selected project , select employee(s) for that task and save.
I am able to save task but not in link table.
Entity classes are,
Employee, Task, Project
Employee
#Entity
#Table(name="Employee")
public class Employee implements Serializable{
#Id
#Column(name="employee_id")
private String employeeId;
#Column(name="employee_name")
private String employeeName;
#ManyToMany(mappedBy="employees")
private Set<Task> tasks;
}
Project
#Entity
#Table(name = "Project")
public class Project implements Serializable {
#Id
#Column(name = "project_id")
private int projectId;
#Column(name = "project_name")
private String projectName;
#OneToMany(cascade = CascadeType.ALL)
#JoinTable(name = "PROJECT_EMPLOYEE",
joinColumns = { #JoinColumn(name = "project_id") },
inverseJoinColumns = { #JoinColumn(name = "employee_id") })
private Set<Employee> employees;
}
Task
#Entity
#Table(name = "Task")
public class Task implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "task_id")
private int taskId;
#Column(name = "task_details")
private String taskDetails;
#Temporal(TemporalType.DATE)
#Column(name = "start_date")
private Date startDate;
#Temporal(TemporalType.DATE)
#Column(name = "end_date")
private Date endDate;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "project_id", nullable = false)
private Project project;
#ManyToMany(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
#JoinTable(name = "Task_Employee", joinColumns = { #JoinColumn(name = "task_id") }, inverseJoinColumns = {
#JoinColumn(name = "employee_id") })
#Embedded
private Set<Employee> employees;
}
Not able to save into Task_Employee table.
Dao code:
From jsp, I am getting all string values and creating task object like this, empView is the view object getting from JSP page and creating Task object to save in dao.
Set<Employee> empSet = new HashSet<Employee>();
for(String employeeId : empView.getEmployees()) {
Employee emp = new Employee();
emp.setEmployeeId(employeeId);
//emp.setEmployeeName("aaa");
//emp.setProject(new Project(empView.getProjectId()));
empSet.add(emp);
}
return new Task(0, empView.getTaskDesc(), new Project(empView.getProjectId()), toDate(empView.getStartDate()),
toDate(empView.getEndDate()), empSet);
Save the above returned task object.
sessionFactory.openSession().save(task);
Thanks