【1】Order与Customer
关联关系映射为Customer:Order = 1:N;Customer可以获取Orders集合,Order不能获取Customer对象。Order表中存在外键-customer_id。
将Order修改如下:
@Table(name="JPA_ORDERS") @Entity public class Order { private Integer id; private String orderName; @GeneratedValue @Id public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } @Column(name="ORDER_NAME") public String getOrderName() { return orderName; } public void setOrderName(String orderName) { this.orderName = orderName; } }
将Customer修改如下:
@NamedQuery(name="testNamedQuery", query="FROM Customer c WHERE c.id = ?") @Cacheable(true) @Table(name="JPA_CUTOMERS") @Entity public class Customer { private Integer id; private String lastName; private String email; private int age; private Date createdTime; private Date birth; public Customer() { } public Customer(String lastName, int age) { super(); this.lastName = lastName; this.age = age; } private Set<Order> orders = new HashSet<>(); // @TableGenerator(name="ID_GENERATOR", // table="jpa_id_generators", // pkColumnName="PK_NAME", // pkColumnValue="CUSTOMER_ID", // valueColumnName="PK_VALUE", // allocationSize=100) // @GeneratedValue(strategy=GenerationType.TABLE,generator="ID_GENERATOR") @GeneratedValue(strategy=GenerationType.AUTO) @Id public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } @Column(name="LAST_NAME",length=50,nullable=false) public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Temporal(TemporalType.TIMESTAMP) public Date getCreatedTime() { return createdTime; } public void setCreatedTime(Date createdTime) { this.createdTime = createdTime; } @Temporal(TemporalType.DATE) public Date getBirth() { return birth; } public void setBirth(Date birth) { this.birth = birth; } //映射单向1-n的关联关系 //使用@OneToMany 映射单向1-n的关联关系 //使用@JoinColumn 来映射外键的名称-Order表中 @JoinColumn(name="CUSTOMER_ID") @OneToMany public Set<Order> getOrders() { return orders; } public void setOrders(Set<Order> orders) { this.orders = orders; } @Transient public String getInfo(){ return "lastName: " + lastName + ", email: " + email; } @Override public String toString() { return "Customer [id=" + id + ", lastName=" + lastName + ", email=" + email + ", age=" + age + ", createdTime=" + createdTime + ", birth=" + birth + "]"; } }
【2】一对多的持久化操作
单向 1-n 关联关系执行保存时, 一定会多出 UPDATE 语句。因为 n 的一端在插入时不会同时插入外键列。
示例代码如下:
@Test public void testOneToManyPersist(){ Customer customer = new Customer(); customer.setAge(18); customer.setBirth(new Date()); customer.setCreatedTime(new Date()); customer.setEmail("mm@163.com"); customer.setLastName("MM"); Order order1 = new Order(); order1.setOrderName("O-MM-1"); Order order2 = new Order(); order2.setOrderName("O-MM-2"); //建立关联关系 customer.getOrders().add(order1); customer.getOrders().add(order2); //执行保存操作 entityManager.persist(customer); entityManager.persist(order1); entityManager.persist(order2); }
控制台输出如下:
Hibernate: insert into JPA_CUTOMERS (age, birth, createdTime, email, LAST_NAME) values (?, ?, ?, ?, ?) Hibernate: insert into JPA_ORDERS (ORDER_NAME) values (?) Hibernate: insert into JPA_ORDERS (ORDER_NAME) values (?) Hibernate: update JPA_ORDERS set CUSTOMER_ID=? where id=? Hibernate: update JPA_ORDERS set CUSTOMER_ID=? where id=?
可以看到三条插入,两条更新语句。
因为如果以1的一端为主的时候,在插入Customer时,order还未插入。order插入时并不会插入外键列。故需要额外两条更新语句。
【3】一对多的获取操作
示例代码如下:
@Test public void testOneToManyFind(){ Customer customer = entityManager.find(Customer.class, 5); System.out.println(customer.getLastName()); System.out.println(customer.getOrders().size()); }
控制台输出如下:
即,默认对关联的多的一方使用懒加载的加载策略.。
可以在Customer类中使用 @OneToMany 的 fetch 属性来修改默认的加载策略。
@JoinColumn(name="CUSTOMER_ID") @OneToMany(fetch=FetchType.EAGER,cascade={CascadeType.REMOVE}) public Set<Order> getOrders() { return orders; }
【4】一对多的删除操作
示例代码如下:
@Test public void testOneToManyRemove(){ Customer customer = entityManager.find(Customer.class, 5); entityManager.remove(customer); }
控制台输出如下:
数据库显示如下:
默认情况下, 若删除 1 的一端, 则会先把关联的 n 的一端的外键置空, 然后进行删除。
可以通过 @OneToMany 的 cascade 属性来修改默认的删除策略。
@JoinColumn(name="CUSTOMER_ID") @OneToMany(fetch=FetchType.EAGER,cascade={CascadeType.REMOVE}) public Set<Order> getOrders() { return orders; }
控制台输出如下:
Hibernate: select customer0_.id as id1_0_1_, customer0_.age as age2_0_1_, customer0_.birth as birth3_0_1_, customer0_.createdTime as createdT4_0_1_, customer0_.email as email5_0_1_, customer0_.LAST_NAME as LAST_NAM6_0_1_, orders1_.CUSTOMER_ID as CUSTOMER3_0_3_, orders1_.id as id1_1_3_, orders1_.id as id1_1_0_, orders1_.ORDER_NAME as ORDER_NA2_1_0_ from JPA_CUTOMERS customer0_ left outer join JPA_ORDERS orders1_ on customer0_.id=orders1_.CUSTOMER_ID where customer0_.id=? Hibernate: update JPA_ORDERS set CUSTOMER_ID=null where CUSTOMER_ID=? Hibernate: delete from JPA_ORDERS where id=? Hibernate: delete from JPA_ORDERS where id=? Hibernate: delete from JPA_CUTOMERS where id=?
看控制台的sql语句即知,先将Orders表中的customer_id设为null,然后将Orders表中的order删除,最后才删除Customer。
【5】一对多的更新操作
示例代码如下:
@Test public void testUpdate(){ Customer customer = entityManager.find(Customer.class, 10); customer.getOrders().iterator().next().setOrderName("O-XXX-10"); }
控制台输出如下: