I have 2 classes called PurchaseList.java and PurchaseListItems.java
I have to map PurchaseList in PurchaseListItems
PurchaseList.java
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name="pl_id",referencedColumnName="id")
private List<PurchaseListItems> purchaseListItems;
PurchaseListItems.java
#ManyToOne
#JoinColumn(name="pl_id")
private PurchaseList purchaseListId;
Everything is fine but i am getting null in pl_id. Please tell where i am wrong
For some reason mapped by didn't work for me with postgres sql and Hibernate4
Below mapping worked
PurchaseList.java
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name="pl_id",nullable=false)
private List<PurchaseListItems> purchaseListItems;
PurchaseListItems.java
#ManyToOne
#JoinColumn(name="pl_id", nullable=false,insertable=false,updatable=false )
private PurchaseList purchaseListId;
Note: you have to use the Identity or Explicitly mention the Sequence for id columns for postgres.
#GeneratedValue(strategy=GenerationType.IDENTITY)
Your mapping actually defines two independent unidirectional relations. What you want is one bidirectional relation.The following code will establish the bidirectional relation
#OneToMany(cascade = CascadeType.ALL, mappedBy = "purchaseListId")
#JoinColumn(name="pl_id",referencedColumnName="id")
private List<PurchaseListItems> purchaseListItems;
The mappedBy attribute is necessary since there is no way for the provider to automatically determine that the specified relations actually form a single relation. One could use the Java type of the instance member but then what if you have multiple members of the same type. And there are many scenarios where you have two single relations. Example:
OneToMany: User -> ForumThread (the threads created by the user)
ManyToOne: ForumThread -> User (the user who closed the thread. obviously not necessarily the one who started the thread)
These are two independent relations and must be treated as such. You would be quite surprised if your persistence provide just made a bidirectional relation out of that just because the types and multiplicity matched.
Also note that bidirectional relations are not automatically managed by any JPA provider, meaning that the inverse side is not automatically updated/set in your object model and thus not in the db. You have to do that yourself. By the way, in all my projects bidirectional relationships were a pain in the ass and I think it is advisable to avoid them.
The #JoinColumn annotation belongs on the #ManyToOne side of the relationship - but not on the #OneToMany side - remove it from the #OneToMany side.
Cascade is used to cascade DELETE/READ/UPDATE operations..., but it does not automatically populate the ID column on the "child" side of a foreign key. In fact, it doesn't populate the java references to objects on either side of the FK relationship. You need to manually setup relationship data on both sides of bidirectional relationships:
myPurchaseListItem.setPurchaseList(myPurchaseList);
myPurchaseList.setPurchaseListItem(myPurchaseListItem);
From the JPA 2 spec:
Bidirectional relationships between managed entities will be persisted based on references held by the owning side of the relationship. It is the developer’s responsibility to keep the in-memory references held on the owning side and those held on the inverse side consistent with each other when they change. In the case of unidirectional one-to-one and one-to-many relationships, it is the developer’s responsibility to insure (sic) that the semantics of the relationships are adhered to.[29]
It is particularly important to ensure that changes to the inverse side of a relationship result in appropriate updates on the owning side, so as to ensure the changes are not lost when they are synchronized to the database.
for(PurchaseListItems item:purchaseListItemsList)
item.purchaseListId(PurchaseList);
This is what I missed when i am creating an object.
Thnaks for your answers
The jpa specification looks good, but verify you have given valid parent to child relationship in the database. If there is not a reference then it will return null.
try this
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "purchaseListId")
Check if you have populated purchaseListId with valid value (a created PurchaseList instance) when you create a PurchaseListItems value.
It's better to use mappedBy as below code to let many-side to maintian the relationship.
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "purchaseListId")
#JoinColumn(name="pl_id",referencedColumnName="id")
private List<PurchaseListItems> purchaseListItems;
Related
I have read some code describing relationship of two entities on both sides which look like following:
public class Department {
#OneToMany(mappedBy = "department",fetch = FetchType.EAGER , cascade = CascadeType.ALL)
private List<Course> courses = new ArrayList<>();
}
public class Course {
#ManyToOne
private Department department;
}
There are two scenarios: When I use relationship annotation on both sides("on both tables Department and Course ") with One-To-Many relationship and When i only use on one side("only table Derpartment). Scenario is similar for Many-To-Many relationship as well.
My question: Should "fetch = FetchType.EAGER , cascade = CascadeType.ALL" be defined only on one side or both sides in the above mentioned scenarios ?
fetch and cascade options can be defined on both sides. If its defined only on one side that it won't have any impact when the other side object is fetched. e.g. If eager fetch is set for courses in Department class but not in Course class then, if a select query is made on department then, it will fetch all its courses along with it But if a select query is made on course then, it won't fetch its associated department unless explicitly called out in query.
Same goes for cascade option. Thus, its definition on either side depends on the kind of queries which are required to be made. If there are going to be a lot of queries on department which needs all the courses information every time but its not the same for fetching a course then, fetch option should be defined only in Department class for courses.
Bi-directional association is good but with additional update in your code for efficient queries i.e. use JoinColumn with #ManyToOne association so that additional association mapping information between two entities doesn't have to be maintained on code side.
I think I misunderstood the meaning of cascading in the context of a #ManyToOne relationship.
The case:
public class User {
#OneToMany(fetch = FetchType.EAGER)
protected Set<Address> userAddresses;
}
public class Address {
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
protected User addressOwner;
}
What is the meaning of the cascade = CascadeType.ALL? For example, if I delete a certain address from the database, how does the fact that I added the cascade = CascadeType.ALL affect my data (the User, I guess)?
The meaning of CascadeType.ALL is that the persistence will propagate (cascade) all EntityManager operations (PERSIST, REMOVE, REFRESH, MERGE, DETACH) to the relating entities.
It seems in your case to be a bad idea, as removing an Address would lead to removing the related User. As a user can have multiple addresses, the other addresses would become orphans. However the inverse case (annotating the User) would make sense - if an address belongs to a single user only, it is safe to propagate the removal of all addresses belonging to a user if this user is deleted.
BTW: you may want to add a mappedBy="addressOwner" attribute to your User to signal to the persistence provider that the join column should be in the ADDRESS table.
You shouldn't use CascadeType.ALL on #ManyToOne since entity state transitions should propagate from parent entities to child ones, not the other way around.
The #ManyToOne is on the child side of the association as it maps the underlying Foreign Key column.
Therefore, you should move the CascadeType.ALL from the #ManyToOne association to the #OneToMany side, which should also use the mappedBy attribute since it's the most efficient one-to-many table relationship mapping.
See here for an example from the OpenJPA docs. CascadeType.ALL means it will do all actions.
Quote:
CascadeType.PERSIST: When persisting an entity, also persist the entities held in its fields. We suggest a liberal application of this cascade rule, because if the EntityManager finds a field that references a new entity during the flush, and the field does not use CascadeType.PERSIST, it is an error.
CascadeType.REMOVE: When deleting an entity, it also deletes the entities held in this field.
CascadeType.REFRESH: When refreshing an entity, also refresh the entities held in this field.
CascadeType.MERGE: When merging entity state, also merge the entities held in this field.
Sebastian
From the EJB3.0 Specification:
Use of the cascade annotation element may be used to propagate the
effect of an operation to associated entities. The cascade
functionality is most typically used in parent-child relationships.
If X is a managed entity, the remove operation causes it to become
removed. The remove operation is cascaded to entities referenced by X,
if the relationships from X to these other entities is annotated with
the cascade=REMOVE or cascade=ALL annotation element value.
So in a nutshell, entity relationships defined with CascadeType.All will ensure that all persistence events such as persist, refresh, merge and remove that occur on the parent, will be passed to the child. Defining other CascadeType options provides the developer with a more granular level of control over how the entity association handles persistence.
For example if I had an object Book that contained a List of pages and I add a page object within this list. If the #OneToMany annotation defining the association between Book and Page is marked as CascadeType.All, persisting the Book would result in the Page also being persisted to the database.
In JPA 2.0 if you want to delete an address if you removed it from a User entity you can add orphanRemoval=true (instead of CascadeType.REMOVE) to your #OneToMany.
More explanation between orphanRemoval=true and CascadeType.REMOVE is here.
If you just want to delete the address assigned to the user and not to affect on User entity class you should try something like that:
#Entity
public class User {
#OneToMany(mappedBy = "addressOwner", cascade = CascadeType.ALL)
protected Set<Address> userAddresses = new HashSet<>();
}
#Entity
public class Addresses {
#ManyToOne(cascade = CascadeType.REFRESH) #JoinColumn(name = "user_id")
protected User addressOwner;
}
This way you dont need to worry about using fetch in annotations. But remember when deleting the User you will also delete connected address to user object.
What exactly is the difference in the following two declarations
B is the owning side
#Entity
class A {
#Id int id;
#OneToOne
B b;
}
#Entity
class B {
#Id int id;
#OneToOne(mappedBy="b")
A a;
}
A is the owning side
#Entity
class A {
#Id int id;
#OneToOne(mappedBy="a")
B b;
}
#Entity
class B {
#Id int id;
#OneToOne
A a;
}
Thinking of this in "normal SQL" i think it is the same as having two tables each having the other table's foreign key. What i don't understand though is what is the effect of specifying which entity is the owning side i.e using the 'mappedBy' property. What does this actually achieve as i don't believe there is an equivalent in normal SQL.
The JPA 2.0 specification, section 2.9, writes:
Relationships may be bidirectional or unidirectional. A bidirectional relationship has both an owning side and an inverse (non-owning) side. A unidirectional relationship has only an owning side. The owning side of a relationship determines the updates to the relationship in the database, as described in section 3.2.4.
The following rules apply to bidirectional relationships:
The inverse side of a bidirectional relationship must refer to its owning side by use of the mappedBy element of the OneToOne, OneToMany, or ManyToMany annotation. The mappedBy element designates the property or field in the entity that is the owner of the relationship.
The many side of one-to-many / many-to-one bidirectional relationships must be the owning side, hence the mappedBy element cannot be specified on the ManyToOne annotation.
For one-to-one bidirectional relationships, the owning side corresponds to the side that contains the corresponding foreign key.
For many-to-many bidirectional relationships either side may be the owning side.
The relevant parts of section 3.2.4 are:
The state of persistent entities is synchronized to the database at transaction commit. This synchronization involving writing to the database any updates to persistent entities and their relationships as specified above.
and
Bidirectional relationships between managed entities will be persisted based on references held by the owning side of the relationship. It is the developer’s responsibility to keep the in-memory references held on the owning side and those held on the inverse side consistent with each other when they change.
In the case of unidirectional one-to-one and one-to-many relationships, it is the developer’s responsibility to insure that the semantics of the relationships are adhered to.
It is particularly important to ensure that changes to the inverse side of a relationship result in appropriate updates on the owning side, so as to ensure the changes are not lost when they are synchronized to the database.
The owning side is the side that JPA considers to know is the association exists or not. Suppose you go with your first example. The owning side is the side where there is no mappedBy attribute. The owning side is thus A, and not B.
This means that if you have an A and a B in database, and you do
A a = em.find(A.class, aId);
B b = em.find(B.class, bId);
a.setB(b);
JPA will save the association (i.e. it will store the ID of B in the join column of table A).
But if you do
A a = em.find(A.class, aId);
B b = em.find(B.class, bId);
b.setA(a);
nothing will be changed in database, because you modified the inverse side and forgot to modify the owning side.
As other have pointed out, you are wrong about which side is the owning side in your examples.
With owning side we mean owning the relationship from an OO perspecitve, in practise that quite often ends up being the opposite of how it is or will be generated in the db if one uses a rdbm as persistence provider.
In normal circumstances the OO model makes it quite clear which sides is the owning side.
For example an Order has OrderLines. If we delete an Order all Orderlines should be deleted. If we delete an OrderLine the Order possibly still has a right to existence.
Hence, the Order is the owning side.
For a more concrete and excellent example, on the effects of which side is the owning side, I refer to #JB Nizet answer.
According to section 2.9 of the JPA 2.0 spec:
For one-to-one bidirectional relationships, the owning side
corresponds to the side that contains the corresponding foreign key.
But in the same section we also have:
In addition, this specification also requires support for the
following alternative mapping strategies: [..] The mapping of
unidirectional and bidirectional one-to-one relationships,
bidirectional many-to-one/one-to-many relationships, and
unidirectional many-to-one relationships by means of join table
mappings.
A bit futher down in the same section it continues with:
Additional mapping annotations (e.g., column and table mapping
annotations) may be speci- fied to override or further refine the
default mappings and mapping strategies described in Section 2.10.
Some implementations make use of that to allow the FK of a birectional OneToOne to be in the target table.
To read some about some strategies to solve that scenario, see: An almost good explaination
I haven't checked but I do hope and believe that 2.1 will remove the first quote. Since the actual database structure should put as little limit as possible on how we can model data as entities.
In the first example the A table is going to have 2 columns id and b_id, the B table is going to have one column, id. This makes A the owning side.
In the second example B is the owning side. B has two columns, id and a_id. A is going to have one column, id.
And that is the difference :-)
How do you implement aggregation and decomposition with Java Persistence API? What are the best practices?
Thanks in advance,
Daniel
I've found the orphanRemoval attribute for #OneToMany and #OneToOne relationships:
When a target entity in one-to-one or one-to-many relationship is removed from the relationship, it is often desirable to cascade the remove operation to the target entity. Such target entities are considered “orphans,” and the orphanRemoval attribute can be used to specify that orphaned entities should be removed. For example, if an order has many line items, and one of the line items is removed from the order, the removed line item is considered an orphan. If orphanRemoval is set to true, the line item entity will be deleted when the line item is removed from the order.
Usage:
#OneToMany(mappedBy="customer", orphanRemoval=true)
public List<Order> orders;
There are two things which should be very clear while handling aggregation in JPA.
The relationship in the relational world.
The relationship required in the object world.
The relationship in Java world is governed by the domain need. For example a User might have many addresses so we keep the make the aggregation of address in User and not keep the inverse relationship. For composition, we need to handle the cascade behavior.
A more detail treatment can be see here
I have a #ManyToMany relationship between two entities. When I perform an update on the owning side, it appears that JPA deletes all the linked records from my database and re-inserts them. For me this is a problem because I have a MySQL trigger that fires before a record is deleted. Any ideas on how to get around this problem?
#Entity
public class User {
#Id
#Column(name="username")
private String username;
...
#ManyToMany
#JoinTable(name="groups", joinColumns=
#JoinColumn(name="username", referencedColumnName="username"),
inverseJoinColumns=#JoinColumn(name="groupname",
referencedColumnName="type_id"))
private List<UserType> types;
...
}
#Entity
public class UserType {
#Id
#Column(name="type_id")
private String id;
#ManyToMany(mappedBy="types")
private List<User> users;
...
}
Use Set instead of List solved the problem. But I have no idea why it works.
Another solution provided by Hibernate is to split the #ManyToMany association into two bidirectional #OneTo#Many relationships. See Hibernate 5.2 documentation for example.
If a bidirectional #OneToMany association performs better when
removing or changing the order of child elements, the #ManyToMany
relationship cannot benefit from such an optimization because the
foreign key side is not in control. To overcome this limitation, the
link table must be directly exposed and the #ManyToMany association
split into two bidirectional #OneToMany relationships.
Try this one:
1) change declaration to:
private List<UserType> types = new Vector<UserType>();
2) never call
user.setTypes(newTypesList)
3) only call
user.getTypes().add(...);
user.getTypes().remove(...);
Its probably related to this question. You have to ensure you have an appropriately defined hashCode an equals method in your mapped object so that Eclipselink can determine equality and thus determine that the existing objects map to existing objects in the DB. Otherwise it has no choice but to recreate the child objects every time.
Alternatively, I've read that this kind of join can only support efficient adding and removing of list items if you use an index column, but that's going to be EclipseLink specific, since the JPA annotations don't seem to support such a thing. I know there is an equivalent Hibernate annotation, but I don't know what it would be in Eclipselink, if such a thing exists.
It appears my problem was that I was not merging the entity.