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.
Related
I have a parent entity like so:
#Entity
public class Parent implements Serializable {
#Id
private String id;
#Convert(converter = ChildConverter.class)
private Collection<Child> children;
...
}
And the child entity is defined like so:
#Entity
public class Child implements Serializable {
#Id
private String id;
...
}
However, I want my Child entity to be saved not in its own table but as a (JSON) column in the Parent table. The reason I want to do this is because the Child entity contains little data and I feel as if it does not warrant its own table. Is this possible for JPA?
Update:
In the end, I've decided to simply not annotate the Child class with #Entity. But the trouble this brings is that I have to enforce entity constraints without JPA's help.
You still need a table to store the children of parents, because you use a Collection in the Parent class.
You may use #Embeddable annotation on Child class and #ElementCollection and #CollectionTable on children Collection in the Parent class.
#Embeddable
public class Child implements Serializable {
#Id
private String id;
...
}
#Entity
public class Parent implements Serializable {
#Id
private String id;
#Convert(converter = ChildConverter.class)
#ElementCollection
#CollectionTable(
name="CHILD",
joinColumns=#JoinColumn(name="PARENT_ID")
private Collection<Child> children;
...
}
I have an entity, that i'd like to join OneToOne with a table with a composite key (Omitting getters/setters):
#Entity
#Table(name = "parent")
public class Parent {
#Id
private String parentId;
#Column(name = "data")
private String data;
#OneToOne
private Child child;
}
And:
#Entity
#IdClass(ChildKey.class)
#Table(name = "child")
public class Child{
#Id
private String parentId;
#Id
private String username;
#Column(name = "data")
private String childData;
}
public class ChildKey implements Serializable {
private String parentId;
private String username;
}
Parent does not have a notion of the 'username' field in the Child entity. I need to pass this in as criteria. In the DB, the primary key of child is on parentId and username.
If I don't specify a JoinColumn, hibernate attempts to map using fields child_username and child_parentId. If I specify only one Joincolumn, I get a broken mapping. If I specify both JoinColumns, I have no column on parent to specify.
How can I map this class and pass in the username as criteria? (it is coming from authentication data) Or how can I do this in a different way if I'm off track.
You might be able to use a Derived Identity.
The Parent class would remain the same; but you would specify a #OneToOne mapping back to the child's parent and the Child and ChildKey classes would look like this:
#Entity
#IdClass(ChildKey.class)
#Table(name = "child")
public class Child{
#Id
#OneToOne(mappedBy="child")
private Parent parent;
#Id
private String username;
#Column(name = "data")
private String childData;
}
public class ChildKey implements Serializable {
private String parent; // name matches name of the #Id field and type matches type of Parent #Id field
private String username; // name and type match those of the #Id field
}
Derived identity is discussed in JPA 2.1 spec, section 2.4.1.
What I ended up doing was defining a #Filter on the Child class, like so:
#Entity
#IdClass(ChildKey.class)
#Table(name = "child")
#FilterDef(name = "usernameFilter", parameters = {
#ParamDef( name = "username", type="string")
})
public class Child { ... }
On the Parent class, I annotated the collection with a reference to the filter:
#OneToMany(fetch = FetchType.EAGER)
#JoinColumn(name = "parentId")
#Filter(name="usernameFilter", condition = "username = :username")
private List<Child> children;
Finally, in my DAO, I parameterized the filter by name like so:
Filter filter = currentSession().enableFilter("usernameFilter");
filter.setParameter("username", user.getUsername());
Doing this resulted in the exact SQL I had in mind, which is an additional clause in the JOIN criteria with a variable:
SELECT
...
FROM
parent this_
LEFT OUTER JOIN
child child_ ON this_.parentId = child_.parentId
AND child_.username = ?
I might not have been clear about what end result I was looking for in my original question. Posting this answer in case it helps someone else.
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.
i want to implement bi-directional One-To-Many relationship in my app engine application. I have two entities - entity A (parent) and entity B(child).
Parent :
#Entity
public class A implements Serializable {
#Id
private String aId;
#OneToMany(mappedBy = "objA", cascade = CascadeType.ALL)
List<B> bList;
getter().........setter()
}
Child :
#Entity
public class B implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Key bId;
#ManyToOne(fetch = FetchType.LAZY)
private A parentA;
getter().........setter()
}
Here,at first i persist object of class A and at that time i don't set its bList property. After that i create object of B and update setbList() of A which will automatically persist object of type B in datastore (as here i have set cascade=CascadeType.ALL).Now i want to access A from B objects.(parent from child) in my endpoint class which i am using in my android client. How can i achieve this?
You just need to add a reference to A in your B class
private A parentA;
parentA = //whatever you use when you update setbList()
Good luck!
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...
}