I am working on JPA project and I need your help.
I have two classes, “Person” and “Leader” which inherits from Person.
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Person implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(unique = true)
private String personId;
}
And
#Entity
public class Leader extends Person implements Serializable {
private List < Person > listTeam;
public void addPersonInTeam(Person e) {
listTeam.add(e);
}
}
My question Is, do I need to have JPA annotations #OneToMany or something else before private List listTeam in class Leader?
Thank you very much
You need to specify a mapping between the two classes because for Hibernate the association is not relevant here, you have to use annotations in both sides and I guess you will need a OneToMany mapping here :
Here's the mapping that you are seraching for:
In Person class:
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Person implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(unique = true)
private String personId;
#ManyToOne
#JoinColumn(name="leader_id")
private Leader leader;
//getter and setter
}
In Leader class:
#Entity
public class Leader extends Person implements Serializable {
#OneToMany(mappedBy = "leader")
private List <Person> listTeam;
//getter and setter
public void addPersonInTeam(Person e) {
listTeam.add(e);
}
}
For further information you can see these links:
Hibernate – One-to-Many example (Annotation).
Hibernate One To Many Annotation tutorial.
Note:
I don't see the use of the field personId in the Person class, there's no need to use two differents ids.
EDIT:
To answer your questions:
The #JoinColumn(name="leader_id") is not mandatory, but it's used to specify the foreign key name.
If the relation is ManyToMany the mappedBy property is used to specify the owner of the relationship, you can see this answer for more details.
Related
I have two child entity, both share the same parent class:
#MappedSuperclass
abstract class Parent {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
}
#Entity
class Child1 extends Parent {
private Integer child1Attr;
}
#Entity
class Child2 extends Parent {
private String child2Attr;
}
And the Parent is supposed to be the "many side" of the #OneToMany relationship, something like this:
#Entity
class MyClass {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#OneToMany
private Set<Parent> allChildSet; // <- hibernate throws exception
}
Is there a way to allow allChildSet accept either child1 or child2 class, since they share the same parent class? Something like this:
#OneToMany(targetEntity = {Child1.class, Child2.class}) // <- not allowed, it only accept one single class
private Set<Parent> allChildSet;
I'm not sure if such feature is possible from the database or ORM's point of view. If not possible, creating a #Transient field, I assume, is the best way to workaround. Any comment or answers are appreciated.
I have a doubt about how the modeling of my entity would be. Come on, I have a table in the database that serves to save documents from my system, this table has the columns id, fk_id (element foreign key), fk_table (entity name) and file_name (stores the name of my file) .
I did a lot of research before posting my question here, but I didn't find anything related to it, what would my entities, user, patient and doctor?
DB:
id
fk_id
fk_table
file_name
1
21
user
test1.jpg
2
32
doctor
test2.pdf
3
61
user
test10.pdf
4
100
patient
test5.jpg
Class:
public class User{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstName;
private String LastName;
// What would a one-to-many relationship look like?
}
public class patient{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstName;
private String lastName;
// What would a one-to-many relationship look like?
}
You can use #Where. But be aware that #Where is a Hibernate annotation. It's not in the JPA standard.
For example in the User entity: (I assume that your table is mapped to an entity called Document)
#Where( clause = "fk_table = 'user'")
#JoinColumn(name = "fk_id")
#OneToMany
private List<Document> documents = new ArrayList<>( );
The following is based only on standard JPA annotations. The idea is to create an inheritance hierarchy for the documents table. The base is:
#Entity
#Table(name = "XX_DOCUMENT")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "fk_table")
public abstract class BaseDocument {
#Id
#GeneratedValue(strategy=SEQUENCE)
private Long id;
#Column(name = "file_name")
private String fileName;
}
Here we define that all entities extending this will go to the same table, with the fk_table column to discriminate. The entities extending it are defined as follows:
#Entity
#DiscriminatorValue("doctor")
public class DoctorDocument extends BaseDocument {
#ManyToOne
#JoinColumn(name = "fk_id")
private Doctor doctor;
}
#Entity
#DiscriminatorValue("patient")
public class PatientDocument extends BaseDocument {
#ManyToOne
#JoinColumn(name = "fk_id")
private Patient patient;
}
// and so on
The interesting thing is that we are reusing the column fk_id to point to the right table. From a small experiment, Hibernate seems to not have problems with it. I would suggest that you manage the DB creation another way just to be safe.
The Doctor, Patient etc need not have a common base class, e.g.:
#Entity
#Table(name = "XX_DOCTOR")
public class Doctor {
#Id
#GeneratedValue(strategy=SEQUENCE)
private Long id;
#OneToMany(mappedBy = "doctor")
private Collection<DoctorDocument> documents = new ArrayList<>();
// any doctor-specific fields
}
#Entity
#Table(name = "XX_PATIENT")
public class Patient {
#Id
#GeneratedValue(strategy=SEQUENCE)
private Long id;
#OneToMany(mappedBy = "patient")
private Collection<PatientDocument> documents = new ArrayList<>();
// any patient-specific fields
}
// and so on
You can read a (doctor, patient, ...)'s documents from the relevant collection. You can even query BaseDocument instances based on any criteria.
You can even go ahead and do more fabcy stuff with the Java code. E.g. define an interface HasDocuments:
public interface HasDocuments<D extends BaseDocument> {
Collection<D> getDocuments();
}
Doctor, Patient, ..., implements this, so they can all be treated the same way.
I'm new to Ebean's world, and I encounter some difficulties to set some relationships between entities.
I have basically two classes, User and Car.
A user can have several cars (so I guess OneToMany) and a car can belongs to one User (so I guess OneToOne).
How can I link these two entities? Here it is what I've done so far
User
#Entity
public class User extends Model{
#Id
#GeneratedValue
public int id;
public String name;
#ManyToMany(cascade=CascadeType.ALL)
public List<Car> car = new ArrayList<Car>();
}
Car
#Entity
public class Car extends Model{
#Id
#GeneratedValue
public int id;
#OneToOne(cascade = CascadeType.ALL)
public User user;
}
And I get the following error
PersistenceException: Error on models.User.car Can not find mappedBy
property [users] in [models.Car]
Can someone explain me clearly how to use annotations the correct way (very poor documentation), and tell me why I get this error?
You guessed wrong :)
Your User should have a #OneToMany relationship with cars so:
#OneToMany(mappedBy = "user", cascade=CascadeType.ALL)
public List<Car> car = new ArrayList<Car>();
while your Car should have a #ManyToOne relationship :
#ManyToOne(cascade = CascadeType.ALL)
public User user;
Take care on the mappedBy property in the #OneToMany annotation: you need to tell Ebean where the foreign key lies in the related class.
User
#Entity
public class User extends Model{
#Id
#GeneratedValue
public int id;
public String name;
#OneToMany(cascade=CascadeType.ALL)
public List<Car> car = new ArrayList<Car>();
}
Car
#Entity
public class Car extends Model{
#Id
#GeneratedValue
public int id;
#ManyToOne(mappedBy="car") //will give you an error
public User user;
}
mappedBy here represents the owner of relation which is important in bidirectional relation.
Think in normal condition can a car exist without the User which owns it means User is the owner in a relation.So in your case User is the owner of relation.Mapped By
But the above code will not work The attribute mappedBy is undefined for the annotation type ManyToOne
In that case #JoinColumn come into picture.Join Column
I've ran into problem with composite primary key handling by Hibernate as a JPA provider.
My entities look like below
// Entity class
#Entity
#IdClass(ExternalMatchPK.class)
#Table(name = "external_match")
public class ExternalMatch {
#Id
#Column(name = "place_id")
private Integer placeId;
#Id
#Column(name = "external_object_id")
private Integer externalObjectId;
// ... Other stuff here
}
// Key class
public class ExternalMatchPK implements Serializable {
private Integer placeId;
private Integer externalObjectId;
}
Looks pretty simple yet no matter what I do I keep getting the following exception (lines are splitted for readability):
org.hibernate.MappingException:
Repeated column in mapping for entity: ExternalMatch
column: external_object_id (should be mapped with insert="false" update="false")
I've tried placing annotation on entity class fields and key class fields together as well as separately, moving all annotations from fields to getters on each one of the classes, using key calss as #Embeddable and putting it into the entity class with #EmbeddedId. Nothing seems to work.
This case seems trivial so maybe it's something wrong with our setup but I can't even imagine where to look for the issue.
Any advice is much appreciated.
It appears that I shot myself in the foot with this.
The issue was that I had a biderectional mapping between ExternalMatch and ExternalObject I forgot about trying to replace the actual entity with its integer id.
So changing
// Entity class
#Entity
#IdClass(ExternalMatchPK.class)
#Table(name = "external_match")
public class ExternalMatch {
#Id
#Column(name = "place_id")
private Integer placeId;
#Id
#Column(name = "external_object_id")
private Integer externalObjectId;
// ... Other stuff here
}
// Key class
public class ExternalMatchPK implements Serializable {
private Integer placeId;
private Integer externalObjectId;
}
// Related entity class
#Entity
#Table(name = "external_object")
public class ExternalObject extends AbstractNameableEntity {
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "external_object_id", nullable = false)
private List<ExternalMatch> matches;
// ...
}
to reprsent actual mappings like this
// Entity class
#Entity
#IdClass(ExternalMatchPK.class)
#Table(name = "external_match")
public class ExternalMatch {
#Id
#ManyToOne
#JoinColumn(name = "external_object_id", referencedColumnName = "id")
private ExternalObject externalObject;
#Id
#ManyToOne
#JoinColumn(name = "place_id")
private Poi place;
// ... Other stuff here
}
// Key class
public class ExternalMatchPK implements Serializable {
private Poi place;
private ExternalObject externalObject;
}
// Related entity class
#Entity
#Table(name = "external_object")
public class ExternalObject extends AbstractNameableEntity {
#OneToMany(cascade = CascadeType.ALL, mappedBy = "externalObject")
private List<ExternalMatch> matches;
// ...
}
resolved the repeated mapping issue yet leaving us with all the familiar troubles a biderectional mapping creates :)
I am new to JPA and am having some difficulty understanding the "Direction in Entity Relationships" concepts as described here:
http://docs.oracle.com/javaee/7/tutorial/doc/persistence-intro001.htm#BNBQI
Is uni- or bidirectionality something that you choose when designing your entities or is it given by the database schema? Like in the order application (http://docs.oracle.com/javaee/7/tutorial/doc/persistence-basicexamples001.htm), could you for example design it so that the lineitem knows about which orders it belongs to, but an order wouldn't know which lineitems it has?
You decide whether a relationship is uni-directional or bi-directional by the fields and annotations you include on the entities.
Uni-directional
#Entity
public class Parent(){
#OneToMany
private List<Child> children;
}
#Entity
public class Child(){
}
Bi-directional
#Entity
public class Parent(){
#OneToMany
private List<Child> children;
}
#Entity
public class Child(){
#ManyToOne
#JoinColumn
private Parent parent;
}
As you can see the uni-directional relationship does not allow the child to access the parent, while the bi-directional does allow parent access. This link is created by adding an annotated field to the child of the parent's type and is completely optional. It boils down to a design decision.
Of course the database must support the relationship, meaning the proper primary/foreign keys are established to link the tables, but nothing special is required in your database.
One important concept to be aware of when modeling these relationships is the owning entity. I have written this article about the topic which may be helpful.
That depend upon your requirement
Unidirectional
#Entity
#AutoProperty
public class OneToOneUnidirectionalA implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
#OneToOne
private OneToOneUnidirectionalB b;
private String s;
// Setters, Getters, Constructors, Pojomatic...
}
#Entity
#AutoProperty
public class OneToOneUnidirectionalB implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
// No reference to OneToOneUnidirectionalA
// since this is a unidirectional relationship
private String s;
// Setters, Getters, Constructors, Pojomatic...
}
Bidirectional
A owns the relationship. We need to avoid Pojomatic circular reference issues too:
#Entity
#AutoProperty
public class OneToOneBidirectionalA implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
#Property(policy=PojomaticPolicy.NONE)
#OneToOne
private OneToOneBidirectionalB b;
// Setters, Getters, Constructors, Pojomatic...
}
#Entity
#AutoProperty
public class OneToOneBidirectionalB implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
#Property(policy=PojomaticPolicy.NONE)
#OneToOne(mappedBy="b")
private OneToOneBidirectionalA a;
// Setters, Getters, Constructors, Pojomatic...
}