I am trying to model a simple OneToMany relationship with EclipseLink JPA & MySQL. It fails with some error messages. Can anyone help me to understand what it is missing ?
#Entity
public class Job implements Serializable {
#Id
#GeneratedValue
private long jobId;
#OneToMany(targetEntity=Applicant.class,mappedBy="job",cascade=CascadeType.ALL)
private List<Applicant> applicant;
//Gettters and Setters
}
#Entity
public class Applicant {
#Id
#GeneratedValue
private long applicantId;
#ManyToOne
#JoinColumn(name="job_Id")
private Job job;
//Gettters and Setters
}
TestCode
Job job=new Job ();
List <Applicant> applicants=new ArrayList<Applicant>();
Applicant applicant=new Applicant();
applicants.add(applicant);
job.setApplicant(applicants);
em.persist(job);// EntityManager Reff
Error message:
Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'job_Id' in 'field list'
You need to have a foreign key column in your Applicant table.
You've annotated relation to Job with #JoinColumn(name="job_Id"). #JoinColumn is not necessary, because JPA is all about convention over configuration, which means there are default values which are implied if you don't override them. Without this annotation, EclipseLink would search for column named job_jobId (<field name>_<id column name in target table>). Since you stated that join column is job_Id, you need to have that column in Applicant table.
These are the database tables that should go with your entity mappings (with #JoinColumn(name = "job_Id")):
TABLE JOB
JOBID (PRIMARY KEY)
TABLE APPLICANT
APPLICANTID (PRIMARY KEY)
JOB_ID (FOREIGN KEY TO JOB#JOBID)
#Entity
public class Job implements Serializable{
#Id
#GeneratedValue
#Column(name="job_id")
private long jobId;
#OneToMany(mappedBy="job",cascade=CascadeType.ALL)
private List<Applicant> applicants;
public Job(){
applicants = new ArrayList<Applicant>();
}
public List<Applicant> getApplicants(){
//force clients through addApplicant() method to encapsulate setting both sides of relationship
return Collections.unmodifiableList(applicants);
}
public void addApplicant(Applicant applicant){
//set both sides of relationship
applicant.setJob(this);
applicants.add(applicant);
}
}
#Entity
public class Applicant {
#Id
#GeneratedValue
private long applicantId;
#ManyToOne
#JoinColumn(name="job_Id")
private Job job;
}
Job job = new Job ();
Applicant applicant = new Applicant();
job.addApplicant(applicant);
em.persist(job);
Related
I like to have a single table ADDRESS in the Database and multiple unrelated entities for example User, Office will have one to many relations with the Address entity. In a nutshell my Entities would looke like
#Entity
public class Address {
#Id
private long id;
#Column
private String entityType; // served as discriminator e-g User,Office ...
#Column
private long entityId; // served as foreign key
... other address columns
}
User Class
public class User {
#Id
private long id;
#OneToMany
private List<Adress> addresses;t
}
Office class
#Entity
public class Office {
#Id
private long id;
#OneToMany
private List<Adress> addresses;
}
I tried #Any of Hibernate but that's not helping with One-to-Many relations. It has either Many-to-One and Many-to-Many relationships. What is the best way to achieve this in JPA.
I have two entities which has separate composite primary keys, Example :-
#Entity
public class Payment
{
#EmbeddedId
private PaymentPK pk1;
private BigInteger amount;
private String countryCode;
}
#Embeddable
public class PaymentPK implements Serializable {
private Long transactionId;
private String type;
}
#Entity
public class tax
{
#EmbeddedId
private TaxPK pk2;
private BigInteger amount;
private String countryCode;
}
#Embeddable
public class TaxPK implements Serializable {
private Long transactionId;
private String taxType;
}
I want to add relationship #ManyToOne, where every payment transaction can have multiple taxes applied to it. The problem here is both entities have different PK, So join on FK is not working(As per my understanding of JPA it allows join on composite key not on part of it). Please help me how to achieve it.I want join based on transactionId attribute.
Parent Table:
#Table(name="parent_table_t")
public class ParentTable implements Serializable {
#Id
#Column(name="contact_id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer contactId;
---------
---------
#OneToOne (cascade = CascadeType.ALL, mappedBy = "parentTable")
private ChildTable childTable;
}
Child Table:
#Table(name="child_table_t")
public class ChildTable implements Serializable {
#Id
#Column(name="child_id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer childId;
#Column(name="contact_id")
private Integer contactId;
#JoinColumn(name="contact_id", referencedColumnName = "contact_id", insertable=false, updatable=false)
#OneToOne(cascade = CascadeType.ALL)
private ParentTable parentTable;
}
My requirement is when contact_id is generated in Parent_table_t, it should be copied into contact_id of child_table_t when saved.
When I am calling saveAndFlush / save on Parent Table Entity, it is:
Generating the auto-increment for Parent->contact_id.
But Child_table_t -> contact_id is always null.
Can someone please help in this.
I am using in-memorty hsqldb with spring-boot and JPA.
You marked the relationship #JoinColumn with insertable=false, updatable=false, likely because you have an integer mapping for the column as well. Unfortunately, these settings prevent JPA from setting it with values from the relationship, which instead is forced to set the column with the value in the contactId attribute.
Put the insertable=false, updatable=false on the #Column instead.
This is my sample schema and I have generated jpa entities in eclipse.
I am using spring jpa repositories. I want to know if I need to create repository interface for student course table.
I am having doubt over addStudentCourse method of both student and course entity classes. List studentCourses will be always null for new entity, how can I fill student course table while registering student information in system i.e save method on studentRepository.
Student.java
#Entity
#NamedQuery(name="Student.findAll", query="SELECT s FROM Student s")
public class Student implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private long studentid;
private String studentname;
//bi-directional many-to-one association to StudentCourse
#OneToMany(mappedBy="student")
private List<StudentCourse> studentCourses;
........
public StudentCourse addStudentCourse(StudentCourse studentCourse) {
getStudentCourses().add(studentCourse);
studentCourse.setStudent(this);
return studentCourse;
}
public StudentCourse removeStudentCourse(StudentCourse studentCourse) {
getStudentCourses().remove(studentCourse);
studentCours.setStudent(null);
return studentCourse;
}
Course.java
#Entity
#NamedQuery(name="Course.findAll", query="SELECT c FROM Course c")
public class Course implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private long courseid;
private String coursename;
//bi-directional many-to-one association to StudentCourse
#OneToMany(mappedBy="course")
private List<StudentCourse> studentCourses;
public StudentCourse addStudentCourse(StudentCourse studentCourse) {
getStudentCourses().add(studentCourse);
studentCourse.setCourse(this);
return studentCourse;
}
public StudentCourse removeStudentCourse(StudentCourse studentCourse) {
getStudentCourses().remove(studentCourse);
studentCourse.setCourse(null);
return studentCourse;
}
StudentCourse.java
#Entity
#Table(name="STUDENT_COURSE")
#NamedQuery(name="StudentCourse.findAll", query="SELECT s FROM StudentCourse s")
public class StudentCourse implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
private StudentCoursePK id;
private String status;
//bi-directional many-to-one association to Course
#ManyToOne
#JoinColumn(name="COURSEID")
private Course course;
//bi-directional many-to-one association to Student
#ManyToOne
#JoinColumn(name="STUDENTID")
private Student student;
...
}
StudentCoursePK.java
#Embeddable
public class StudentCoursePK implements Serializable {
//default serial version id, required for serializable classes.
private static final long serialVersionUID = 1L;
#Column(insertable=false, updatable=false)
private long studentid;
#Column(insertable=false, updatable=false)
private long courseid;
...
}
If I understood your question correctly what you want to do is to be able to save a student from the save method in StudentRepository, and that this inserts/updates the student and also inserts/updates the join table.
Since the Student entity is not the owning side (it's mapped by "student" in StudentCourse), saving a Student will not trigger a save on StudentCourse. To do so you can add a cascade property the list for insert, update... or just for everything:
#OneToMany(mappedBy="student", cascade = CascadeType.ALL)
private List<StudentCourse> studentCourses = new ArrayList<StudentCourse>();
Then you could a method on your #Service class that looks like this:
#Transactional
public void enrollInCourse(Student student, Course course) {
StudentCourse sc = new StudentCourse();
sc.setStudent(student);
sc.setCourse(course);
sc.setStatus("Enrolled");
student.getStudentCourses().add(sc);
studentRepository.save(student);
}
This will also populate the StudentCourse table.
So there's no need for a repository, although if the cascade doesn't work as expected you could create one and save the StudentCourse entity yourself manually.
If this does not work you could try changing your mappings. For n-ary relationships or join tables with extra columns I always define the #ManytoOne relationships inside the #Embeddable class, and in the entity that represents the join table I define getters as #Transient to allow access to the mapped objects which are inside the embedded composite Id.
You can see an example here, and a blog post about this approach here.
I would like some advice on how to best layout my JPA entity classes. Suppose I have 2 tables I would like to model as entities, user and role.
Create Table users(user_id primary key,
role_id integer not null )
Create table role(role_id primary key,
description text,
)
I create the following two JPA Entities:
#Entity
#Table(name="users")
#Access(AccessType.PROPERTY)
public class User implements Serializable {
private Long userId;
private Long roleId;
private Role role;
#Column(name = "user_id")
#Id
public Long getUserId() {}
#Column(name = "role_id")
public Long getRoleId() {}
#ManyToOne()
JoinColumn(name="role_id")
public Role getRole() {}
}
Role Entity:
#Entity
#Table(name="Role")
#Access(AccessType.PROPERTY)
public class Role implements Serializable {
private String description;
private Long roleId;
#Column(name = "role_id")
#Id
public Long getRoleId() {}
#Column(name = "description")
public Long getDescrition(){}
#ManyToOne()
#JoinColumn(name="role_id")
public Role getRole() {}
}
Would the correct way to model this relationship be as above, or would I drop the private Long roleId; in Users? Any advice welcomed.
When I map it this way, I receive the following error:
org.hibernate.MappingException: Repeated column in mapping for entity:
Yes, you would drop the private Long roleId mapping when you have a #ManyToOne on the same column.
As the error implies, you can only map each column in an #Entity once. Since role_id is the #JoinColumn for the #ManyToOne reference, you cannot also map it as a property.
You can, however, add a convenience method to return the role ID, like
public Long getRoleId() {
return role.getId();
}