import
java.util.List;
import
javax.persistence.*;
@Entity
public
class
Person {
@Id
@GeneratedValue
private
int
id;
private
String name;
@OneToMany
(mappedBy =
"person"
)
private
List
dogs;
// get and set
}
import
java.util.List;
import
javax.persistence.*;
@Entity
public
class
Dog {
@Id
@GeneratedValue
private
int
id;
44 of 60
JPA Mini Book
www.javacodegeeks.com
private
String name;
@OneToMany
(mappedBy =
"dog"
)
private
List
persons;
// get and set
}
The code above is using the @OneToMany relationship with the mappedBy option. Notice that there is no
@ManyToMany relationship between the entities, but there is an entity PersonDog that unite both entities.
Below is the PersonDog code:
import
java.util.Date;
import
javax.persistence.*;
@Entity
@IdClass
(PersonDogId.
class
)
public
class
PersonDog {
@Id
@ManyToOne
@JoinColumn
(name=
"person_id"
)
private
Person person;
@Id
@ManyToOne
@JoinColumn
(name=
"dog_id"
)
private
Dog dog;
@Temporal
(TemporalType.DATE)
private
Date adoptionDate;
// get and set
}
In the code above you can see the relationships between PersonDog, Dog and Person, and an extra attribute to
store the adoption date. There is an id class to store the relationship ids named "PersonDogId":
import
java.io.Serializable;
public
class
PersonDogId
implements
Serializable {
private
static
final
long
serialVersionUID = 1L;
private
int
person;
private
int
dog;
public
int
getPerson() {
return
person;
}
45 of 60
JPA Mini Book
www.javacodegeeks.com
public
void
setPerson(
int
person) {
this
.person = person;
}
public
int
getDog() {
return
dog;
}
public
void
setDog(
int
dog) {
this
.dog = dog;
}
@Override
public
int
hashCode() {
return
person + dog;
}
@Override
public
boolean
equals(Object obj) {
if
(obj
instanceof
PersonDogId){
PersonDogId personDogId = (PersonDogId) obj;
return
personDogId.dog == dog && personDogId.person == person;
}
return
false
;
}
}
One thing to notice here is that person and dog attributes must have the same name - "person" and "dog" here -
between the PersonDogId and PersonDog entities. It is how JPA works. More information about complex keys can
be found at earlier sections of this document.
How the Cascade functionality works? How should a
developer use the OrphanRemoval? Handling the
org.hibernate.TransientObjectException
It is very common two or more entities to receive updates in the same transaction. When editing a person's data for
example, we could change their name, address, age, car color etc. These changes should trigger updates to three
different entities: Person, Car and Address.
The updates above could be done as shown in the code snippet below:
car.setColor(Color.RED);
car.setOwner(newPerson);
car.setSoundSystem(newSound);
46 of 60
JPA Mini Book
www.javacodegeeks.com
If the code below were to be executed the exception org.hibernate.TransientObjectException would be thrown:
EntityManager entityManager =
// get a valid entity manager
Car car =
new
Car();
car.setName(
"Black Thunder"
);
Address address =
new
Address();
address.setName(
"Street A"
);
entityManager.getTransaction().begin();
Person person = entityManager.find(Person.
class
,
33
);
person.setCar(car);
person.setAddress(address);
entityManager.getTransaction().commit();
entityManager.close();
With the EclipseLink JPA implementation the following message would be fired: “
Caused by:
java.lang.IllegalStateException: During synchronization a new object was found through a relationship that was not marked
cascade PERSIST”
.
What means that an entity is transient? Or what a relationship not marked with cascade persist is all about?
JPA works as a tracker for every entity that participates in a transaction. An entity that participates in a transaction is
an entity that will be created, updated, deleted. JPA needs to know where that entity came from and where it is
going to. When a transaction is opened every entity brought from the database is “attached”. With “attached” we
mean that the entity is inside a transaction, being monitored by JPA. An entity remains attached until the transaction
is closed (rules for JSE applications or transactions without EJB Stateful Session Beans with Persistence Scope
Extended are different); to be attached an entity needs to come from a database (by query, entity manager find
method…), or receive some contact inside the transaction (merge, refresh).
Notice the code below:
entityManager.getTransaction().begin();
Car myCar = entityManager.find(Car.
class
,
33
);
myCar.setColor(Color.RED);
entityManager. getTransaction().commit();
The transaction is opened, an update is made in the entity and the transaction is committed. It was not required to
do an explicit update to the entity, with the transaction committing all updates made to the entity will be persisted to
the database. The updates made to the Car entity were persisted to the database because the entity is attached,
any update to an attached entity will be persisted in the database after the transaction commits() or a flush call is
made.
47 of 60
JPA Mini Book
www.javacodegeeks.com
As shown In the code snippet above "myCar" entity was brought from the database inside a transaction, thus JPA
will have the "myCar" entity attached into that Persistence Context. It is possible to define a Persistence Context as
a place where JPA will put all attached entities to that transaction, or as a big bag. The images below show this
concept:
48 of 60
JPA Mini Book
www.javacodegeeks.com
Notice in the image above that the Car entity is added to the Persistence Context only after a database query is
performed to retrieve it from the database. Every update in the Car entity will be monitored by JPA. Once the
transaction is finished (or the flush command invoked), JPA will persist this changes to the database.
The aforementioned problem occures when we update a relationship between two entities. Check the code and the
image below:
entityManager.getTransaction().begin();
Person newPerson =
Do'stlaringiz bilan baham: |