Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do I have to persist both objects if Address is nested in User?

Tags:

java

jpa

I am trying to better familiarize myself with JPA so I created a very simple project. I have a User Class and an Address class. It appears that I have to persist both even though I am adding Address to my User class?

User:

import javax.persistence.*;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Entity
@Table(name = "usr") // @Table is optional, but "user" is a keyword in many SQL variants 
@NamedQuery(name = "User.findByName", query = "select u from User u where u.name = :name")
public class User {
    @Id // @Id indicates that this it a unique primary key
    @GeneratedValue // @GeneratedValue indicates that value is automatically generated by the server
    private Long id;

    @Column(length = 32, unique = true)
    // the optional @Column allows us makes sure that the name is limited to a suitable size and is unique
    private String name;

    // note that no setter for ID is provided, Hibernate will generate the ID for us

    @OneToMany(fetch=FetchType.LAZY, mappedBy="user")
    private List<Address> addresses;

Address:

@Entity
public class Address {

    @Id // @Id indicates that this it a unique primary key
    @GeneratedValue // @GeneratedValue indicates that value is automatically generated by the server
    private Long id;

    @Column(length=50)
    private String address1;

    @ManyToOne
    @JoinColumn(name="user_id")
    private User user;

EntityManager:

EntityManager entityManager = Persistence.createEntityManagerFactory("tutorialPU").createEntityManager();

entityManager.getTransaction().begin();

User user = new User();
user.setName("User");

List<Address> addresses = new ArrayList<Address>();
Address address = new Address();
address.setAddress1("Address1");

addresses.add(address);
user.setAddresses(addresses);
entityManager.persist(user);
entityManager.persist(address);
entityManager.getTransaction().commit();
entityManager.close();

Probably doing something wrong...just not sure what it is?

Any suggestions would be appreciated.

Thanks,

S

like image 610
scarpacci Avatar asked Sep 28 '12 14:09

scarpacci


2 Answers

Try the cascade element for the annotation.

@OneToMany(fetch=FetchType.LAZY, mappedBy="user", cascade=CascadeType.PERSIST) 
private List<Address> addresses; 

The documentation says that by default no operation is cascaded. It also states that the cascade operation is optional, so it really depends on the implementation that you are using.

Also, while setting the relationship, make sure you set both sides of the relationship. Set addresses to the user and user to the addresses.

like image 176
Bhesh Gurung Avatar answered Oct 18 '22 16:10

Bhesh Gurung


What you're talking about it's called Cascading. That means doing the same action to nested objects, such as an Address in your User. By default, there is no cascading at all if you don't specify any CascadeType.

You can define various cascade types at once

@OneToMany(fetch=FetchType.LAZY, mappedBy="user", cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE})
private List<Address> addresses;

or just tell JPA to cascade every operation:

@OneToMany(fetch=FetchType.LAZY, mappedBy="user", cascade = CascadeType.ALL)
private List<Address> addresses;

Both ways will result in, for example, a persisted Address while persisting an User or the deletion of the associated Address when an User is removed.

But!... if you remove CascadeType.REMOVE from the first example, removing an User won't remove its associated Address (The removal operation won't be applied to nested objects).

like image 36
Fritz Avatar answered Oct 18 '22 15:10

Fritz