I have an entity Person with a relation to an other person (mentor). This person can be null. I thought just the Constraints.Required annotation forces my mentor to be set.
If I remove the ManyToOne annotation the mentor wont be connected.
#Entity
public class Person extends Model {
#Id
#Constraints.Required
#Formats.NonEmpty
public Integer id;
#ManyToOne
#Constraints.Required
public User user;
#Constraints.Required
public String firstName;
#Constraints.Required
public String lastName;
#ManyToOne
public Person mentor;
...
How can I have a person without a mentor?
The usage of the #ManyToOne annotation is actually "instructing" your JPA provider th think that the Person table/relation has a foreign key to it (this models the 1:n relation b/n persons to mentors and a foreign key can't be null) but from your question, I see your biz needs doesn't need a 1:n per se so simply remove the #ManyToOne annotation and on case a person does have a mentor , wire this relation manually in the JPA entity constructor or via setter method
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 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);
I want to define a table where the entire record is the primary key. The table has two columns which are references to other entities.
#Entity
public class ProtoList implements Serializable {
#Id
#ManyToOne ProtoObject listID;
#Id
#OneToOne ProtoObject po;
ProtoObject is an entity whose #Id is a regular generated Long.
The resulting relational data structure is intended allow any ProtoObject to be associated with an arbitrarily long List (actually a Set) of ProtoObjects. So the two table columns are just two Longs, always unique.
Will this work or do I have to define an #IdClass or something else?
After some experimentation I discovered that it was indeed necessary to use an #IdClass annotation. What is interesting is that in the Entity itself I have the #ManyToOne and #OneToOne annotations to create relational links to ProtoObjects, but in the IdClass the corresponding fields are inferred from the ProtoObject's own ID field.
So the result is:
#Entity
#IdClass(ProtoListKey.class)
public class ProtoList implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#ManyToOne ProtoObject listID;
#Id
#OneToOne ProtoObject po;
And the key is:
public class ProtoListKey {
private Long listID;
private Long po;
The primary key of ProtoList is Long so this works. The entire record is the primary key which is what I wanted. Lesson learned.
I have a User class:
#Entity
public class User extends Model {
#Id
public Long id;
public String email;
public String name;
public String password;
}
and a driver class
#Entity
public class Driver extends Model {
#Id
public Long id;
#OneToOne (cascade = CascadeType.ALL)
#Column(unique = true)
public User user;
}
I want to make sure that the user_id is unique inside the Drivers table. But the code above does not enforce that. (I can create multiple drivers with the same user id).
Ideally, I do not want to add the #OneToOne relations in the User class because there are several different roles inside my app (e.g. driver, teacher, agent etc.) and I don't want to pollute user class with all those relations.
How can I achieve this?
I have tried this code on the model for me, and it worked. One thing to be noted, that you must use #OneToOne annotation to let the ORM knows that you have foreign key reference to other model.
The model look like following:
#Entity
// add unique constraint to user_id column
#Table(name = "driver",
uniqueConstraints = #UniqueConstraint(columnNames = "user_id")
)
public class Driver extends Model {
#Id
public Long id;
#OneToOne
#JoinColumn(name = "user_id")
public User user;
}
It will generate evolution script like this :
create table driver (
id bigint not null,
user_id bigint,
constraint uq_driver_1 unique (user_id), # unique database constraint
constraint pk_driver primary key (id)
);
So, with this method you can make sure that you will have unique user reference on driver table.
Additional Info
Because there is an additional constraint, that is not handled by framework but by the database applied on the model (such as the unique constraint), to validate the input or handling the occurred exception, you can surround Model.save() or form.get().save() expression (saving-the-model) with try-catch block to handle the PersistenceException.
I have several questions on bidirectional mapping.
I have these entities:
Employee(1) - (1) Parking_Lot
Employee(*) - (1) Department
Employee(*) - (1) Project
What is the source and target entity for the above relationship?
What is the owner for ManyToOne relationship. I wonder the owner is
on Many entity or One entity?
Do mappedBy specify on owner side or inverse side?
Please help.
EDIT:
I have the following table:
Project - Proj_Client - Client (Many to Many relationship) and persist the project table but the client is not get persist. What wrong with it?
Thanks.
#Entity
#Table(name="empoyee")
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#ManyToOne
#JoinColumn(name="department_id", referencedColumnName="id")
private Department department;
#ManyToOne
#JoinColumn(name="project_id", referencedColumnName="id")
private Project projects;
#OneToOne(mappedBy="employee")
private ParkingLot parkingLot;
//Other properties,constructors, getters and setters and so on
}
#Entity
#Table(name="department")
public class Department implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#OneToMany(mappedBy="department")
private List<Employee> employees;
//Other properties,constructors, getters and setters and so on}
#Entity
#Table(name="parking_lot")
public class ParkingLot implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#OneToOne
#JoinColumn(name="employee_id",referencedColumnName="id")
private Employee employee;
//Other properties,constructors, getters and setters and so on}
#Entity
#Table(name="project")
public class Project implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#OneToMany(mappedBy="project")
private List<Employee> employees;
//Other properties,constructors, getters and setters and so on
}
If the relationship is unidirectional there really isn't an owning side, and there isn't any mappedBy annotations.
If the relationship is bidirectional there is a side with the mappedBy annotation - the other side is the owning side.
The owning side is the side that owns the relationship. So the term is not ment to be applied like a ParkingLot owns its Employee or an Employee owns its ParkingLot, but rather like the relationship between ParkingLot and Employee is owned by the Employee (or ParkingLot see below).
For ManyToOne there is no mappedBy, so it is always the entity specified under the OneToMany annotation that owns the relationship (makes sense, since the for example the project table can't have foreign keys to all its employees)
So for the two ManyToOne/OneToMany mappings in your example we don't have a choice in which side owns the relationship. Between Employee and ParkingLot we have a choice, I choosed ParkingLot.
When given a choice, what does it matter? Well, the main difference is that the mappedBy have the porperty cascade. Please note that it doesn't matter which table have the foreign key, or if the relationship is in its own table - JPA supports all cases (#InverseJoinColumn etc).
For bidirectional mappings there isn't a clear target and source for the mapping, it depends on which way you at the mapping from. The term is more applicable to unidirectional mappings, and there the source side is of course the entity with the mapping (that is possible knowledge of the target entity)
4) Not applicable (unless you make the relationship between ParkingLot and Employee unidirectional).
5) The owner of the relationship is always "on the One entity"
6) inverse side
Final note:
"owning side" is confusing, for example we could design so that a Department owns its Employees and if we delete a Department all its employees would also be deleted. This would be done by changing #OneToMany(mappedBy="department") into #OneToMany(mappedBy="department", cascade= CascadeType.REMOVE) then it would really make sense to say "the Department entity owns its Employee entities" but the relationship would still be owned by the Employee entity.