实体bean(十二)一对一映射
@OneToOne的四个属性
1.targetEntity
targetEntity 属性是 Class 类型的属性。定义实体一对一关系中处于从属地位的实体类的类型。
2.mappedBy
mappedBy 属性是 String 类型的属性。mappedBy 属性的值是当前实体在关联实体中的属性名称,使用 mappedBy 可以定义实体类之间的双向关系。如果类之间是单向关系,不需要提供定义,如果类和类之间形成双向关系,我们就需要使用这个属性进行定义,否则可能引起数据一致性的问题。
3.cascade
cascade 属性的类型是 CascadeType[] 类型。cascade 属性定义实体和实体之间的级联关系。使用 cascade 属性定义的级联关系将被容器视为对当前类对象及其关联类对象采取相同的操作,而且这种关系是递归调用的。
cascade 的值只能从 CascadeType.PERSIST(级联新建)、CascadeType.REMOVE(级联删除)、CascadeType.REFRESH(级联刷新)、CascadeType.MERGE(级联更新)中选择一个或多个。还有一个更方便的选择是使用 CascadeType.ALL,表示选择上面全部四项。
4.fetch
fetch 属性是 FetchType 类型的属性。可选择项包括:FetchType.EAGER 和 FetchType.LAZY.前者表示关联关系的从类在主类加载的时候同时加载,后者表示关联关系的从类在自己被访问时才加载。默认值是 FetchType.EAGER.
5.optional
optional 属性是 boolean 类型的属性。optional 属性用于定义关联关系的从类对象是否必须存在。如果设置为 false,那么该属性就不能设置为 null.默认值是 true。注释的 optional 属性设为 True 表示该对象可以不存在。
package com.persia.jpa; import java.io.Serializable; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToOne; import javax.persistence.Table; @Entity @Table(name="person") public class Person implements Serializable { private Integer id; private String name; private Short age; private Address address; @Id @GeneratedValue(strategy=GenerationType.AUTO) public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } @Column(name="personname",nullable=false,length=32) public String getName() { return name; } public void setName(String name) { this.name = name; } public Short getAge() { return age; } public void setAge(Short age) { this.age = age; } @OneToOne(optional=true,cascade=CascadeType.ALL,mappedBy="person") public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } }
-------------------------------------------------------------------------------------------------------------------------
1.javax.persistence.JoinColumn 注释可以和 javax.persistence.OneToOne 注释一起使用,用于定义关联关系中的主类在数据库中对应的表
通过什么字段和关联关系中的从类的主键进行关联,这个注释是可选的,如果不提供该注释,OpenJPA 会默认使用“对象名_ID”和关联表的主键
字段进行关联。
2.JoinColumn 注释支持两个重要属性:name 和 referencedColumnName 属性。
(1)name
name 属性的类型是 String 类型。name 属性用于指定关联关系中的主类对应的表中和关联关系中的从类的主键进行关联的字段的名称。
(2)referencedColumnName
referencedColumnName 属性的类型是 String 类型。referencedColumnName 属性指定关联关系中的从类与关联关系中的主类对应的表
之间形成关联关系的字段名称,通常用于关联关系中的从类的关联字段不是自己的主键的情况。
package com.persia.jpa; import java.io.Serializable; import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.OneToOne; import javax.persistence.Table; @Entity @Table(name="address") public class Address implements Serializable { private Integer id; private String city; private String street; private Person person; @Id @GeneratedValue(strategy=GenerationType.AUTO) public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public String getStreet() { return street; } public void setStreet(String street) { this.street = street; } @OneToOne(optional=false,cascade=CascadeType.ALL) @JoinColumn(name="person_id",referencedColumnName="id",unique=true) public Person getPerson() { return person; } public void setPerson(Person person) { this.person = person; } }
使用 JoinColumn 注释设置两个对象对应数据库表之间的关联字段
name 属性指定关联关系中主类对应表中参与关联关系的字段名称,
referencedColumnNam 属性指定关联关系中从类对应表中参与关联关系的字段名称。
--------------------------------------------------------------------
实体操作:
package com.persia.jpa; import javax.ejb.Remote; import javax.ejb.Stateless; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; @Stateless @Remote({OneToOneDAO.class}) public class OneToOneDAOBean implements OneToOneDAO { @PersistenceContext private EntityManager em; @Override public void deleteAddress(Integer id) { // TODO Auto-generated method stub Address a=em.find(Address.class, id); em.remove(a); } @Override public void deletePerson(Integer id) { // TODO Auto-generated method stub Person p=em.find(Person.class,id); em.remove(p); } @Override public Person getPersonByID(Integer id) { // TODO Auto-generated method stub Person p=em.find(Person.class,id); return p; } @Override public void insertPerson(String name, short age, String city, String street) { // TODO Auto-generated method stub Person p=new Person(); p.setName(name); p.setAge(age); Address address=new Address(); address.setCity(city); address.setStreet(street); address.setPerson(p); p.setAddress(address); em.persist(p); } @Override public void updatePersonInfo(Integer id, String newname, String newstreet) { // TODO Auto-generated method stub Person p=em.find(Person.class,id); p.setName(newname); Address a=p.getAddress(); a.setStreet(newstreet); } }
疑问:在updatePersonInfo中不需要merge吗?
如果是在客户端来setter设置的话,需要merge。
-------------------------------------------------------------------------------------------------------------------------------------
客户端:
package com.persia.jpa.test; import java.util.Properties; import javax.naming.InitialContext; import javax.naming.NamingException; import com.persia.jpa.oto.OneToOneDAO; import com.persia.jpa.oto.Person; public class Test { /** * @param args * @throws NamingException */ public static void main(String[] args) throws NamingException { Properties props=new Properties(); props.setProperty("java.naming.factory.initial","org.jnp.interfaces.NamingContextFactory"); props.setProperty("java.naming.provider.url","localhost:1099"); props.setProperty("java.naming.factory.url.pkgs","org.jboss.naming"); InitialContext context=new InitialContext(props); try{ OneToOneDAO dao=(OneToOneDAO)context.lookup("OneToOneDAOBean/remote"); // dao.insertPerson("persia",new Short((short)26), "beijing", "shangdi"); //dao.insertPerson("linda", new Short((short)26), "beijing", "shangdi"); // dao.deletePerson(new Integer(8)); Person p=dao.getPersonByID(new Integer(5)); System.out.println(p.getName()+"-"+p.getAddress().getStreet()); dao.updatePersonInfo(new Integer(5), "persiacai", "fujian"); dao.deleteAddress(new Integer(10)); }catch(Exception e){ e.printStackTrace(); } } }由于person和address双向关联而且级联,删除任何一者都对应删除另一方。