※準備工作
DROP TABLE PERSON_TOILET PURGE; DROP TABLE TOILET PURGE; DROP TABLE PERSON PURGE; CREATE TABLE PERSON( PID NUMBER(5), PNAME VARCHAR(20), CONSTRAINT PERSON_PK PRIMARY KEY(PID) ); CREATE TABLE TOILET( TID NUMBER(5), TNAME VARCHAR(20), CONSTRAINT TOILET_PK PRIMARY KEY(TID) ); CREATE TABLE PERSON_TOILET( PT_ID NUMBER(5), PERSON_ID NUMBER(5), TOILET_ID NUMBER(5), CONSTRAINT PERSON_TOILET_PK PRIMARY KEY(PT_ID), CONSTRAINT FK_PID FOREIGN KEY(PERSON_ID) REFERENCES PERSON(PID) ON DELETE CASCADE, CONSTRAINT FK_TID FOREIGN KEY(TOILET_ID) REFERENCES TOILET(TID) ON DELETE CASCADE ); CREATE SEQUENCE TOILET_SEQ; CREATE SEQUENCE PERSON_SEQ; CREATE SEQUENCE PERSON_TOILET_SEQ;
※在關聯表加個主鍵
※XML設定
Person.java
public class Person { private Integer pid; private String pname; private Set<PersonToilet> personToilets = new HashSet<>(); // setter/getter... }
Toilet.java
public class Toilet { private Integer tid; private String tname; private Set<PersonToilet> personToilets = new HashSet<>(); // setter/getter... }
PersonToilet.java
public class PersonToilet { private Integer ptId; private Person centerPerson; private Toilet centerToilet; // setter/getter... }
Person.hbm.xml
<class name="vo.Person" table="PERSON"> <id name="pid" type="java.lang.Integer"> <column name="PID" /> <generator class="sequence"> <param name="sequence">PERSON_SEQ</param> </generator> </id> <property name="pname" type="java.lang.String" column="PNAME" /> <set name="personToilets" inverse="true" cascade="all" lazy="false"> <key column="PERSON_ID" /> <one-to-many class="vo.PersonToilet" /> </set> </class>
Toilet.hbm.xml
<class name="vo.Toilet" table="TOILET"> <id name="tid" type="java.lang.Integer"> <column name="TID" /> <generator class="sequence"> <param name="sequence">TOILET_SEQ</param> </generator> </id> <property name="tname" type="java.lang.String" column="TNAME" /> <set name="personToilets" inverse="true" cascade="all" lazy="false"> <key column="TOILET_ID" /> <one-to-many class="vo.PersonToilet" /> </set> </class>
PersonToilet.hbm.xml
<class name="vo.PersonToilet" table="PERSON_TOILET"> <id name="ptId" type="java.lang.Integer"> <column name="PT_ID" /> <generator class="sequence"> <param name="sequence">PERSON_TOILET_SEQ</param> </generator> </id> <many-to-one name="centerPerson" column="PERSON_ID" lazy="false" not-null="true" cascade="all" class="vo.Person" /> <many-to-one name="centerToilet" column="TOILET_ID" lazy="false" not-null="true" cascade="all" class="vo.Toilet" /> </class>
新增測試
Session s = HibernateUtil2.getSession(); Transaction tx = s.beginTransaction(); try { Toilet t1 = new Toilet(); t1.setTname("便所1號"); Toilet t2 = new Toilet(); t2.setTname("便所2號"); Toilet t3 = new Toilet(); t3.setTname("便所3號"); Person p1 = new Person(); p1.setPname("掃便所英俠"); Person p2 = new Person(); p2.setPname("茅坑王"); // 因為掃便所英俠可以上3間廁所,而茅坑王可以上2間廁所,所以要創5個實體 PersonToilet pt1 = new PersonToilet(); PersonToilet pt2 = new PersonToilet(); PersonToilet pt3 = new PersonToilet(); PersonToilet pt4 = new PersonToilet(); PersonToilet pt5 = new PersonToilet(); // -----設定互相關聯----- // 掃便所英俠(p1)可以上便所1號(t1) // 此時的中間表就代替了Toilet的位置,然後自己在去關聯Toilet p1.getPersonToilets().add(pt1); pt1.setCenterPerson(p1); pt1.setCenterToilet(t1);// 就是這時去關聯Toilet t1.getPersonToilets().add(pt1); // 掃便所英俠(p1)可以上廁所2號(t2) p1.getPersonToilets().add(pt2); pt2.setCenterPerson(p1); pt2.setCenterToilet(t2); t2.getPersonToilets().add(pt2); // 掃便所英俠(p1)可以上廁所3號(t3) p1.getPersonToilets().add(pt3); pt3.setCenterPerson(p1); pt3.setCenterToilet(t3); t3.getPersonToilets().add(pt3); // 茅坑王(p2)可以上廁所1號(t1) p2.getPersonToilets().add(pt4); pt4.setCenterPerson(p2); pt4.setCenterToilet(t1); t1.getPersonToilets().add(pt4); // 茅坑王(p2)可以上廁所3號(t3) p2.getPersonToilets().add(pt5); pt5.setCenterPerson(p2); pt5.setCenterToilet(t3); t3.getPersonToilets().add(pt5); s.save(pt1); s.save(pt2); s.save(pt3); s.save(pt4); s.save(pt5); tx.commit(); } catch (Exception e) { tx.rollback(); System.err.println("例外錯誤!"); e.printStackTrace(); } finally { if (s.isOpen()) { s.close(); } }
修改Person測試
Person person = (Person) s.get(Person.class, 114);// 掃便所英俠的ID person.setPname("吸茅坑大王"); for (PersonToilet pt : person.getPersonToilets()) { Toilet t = pt.getCenterToilet(); t.setTname("廁" + t.getTname().substring(1)); } s.update(person); tx.commit();
修改Toilet測試
Toilet toilet = (Toilet) s.get(Toilet.class, 184);// 便所1號的ID toilet.setTname("廁所1號"); for (PersonToilet pt : toilet.getPersonToilets()) { Person p = pt.getCenterPerson(); p.setPname("臭臭王"); } s.update(toilet); tx.commit();
查詢測試
// 查詢掃便所英俠能用哪些廁所 Person p = (Person) s.get(Person.class, 114);// 掃便所英俠的ID s.close(); System.out.println(p.getPname()); // 必需在Person.hbm.xml和PersonToilet.hbm.xml的centerToilet設定lazy="false" for (PersonToilet pt : p.getPersonToilets()) { System.out.println(pt.getCenterToilet().getTname()); } // 查詢便所1號能被哪些人使用 Toilet t = (Toilet) s.get(Toilet.class, 184);// 便所1號的ID s.close(); System.out.println(t.getTname()); // 必需在Toilet.hbm.xml和PersonToilet.hbm.xml的centerPerson設定lazy="false" for (PersonToilet pt : t.getPersonToilets()) { System.out.println(pt.getCenterPerson().getPname()); }
刪除測試
Person person = (Person) s.get(Person.class, 114); s.delete(person); tx.commit(); Toilet toilet = (Toilet) s.get(Toilet.class, 185); s.delete(toilet); tx.commit();
※刪除很奇怪,我把三張表的4個cascade拿掉或設none才會成功,中間表也會刪
※結論:
關聯表有沒有主鍵最大的差異就是要不要將關聯表建立出來,但如果像現在這個例子只有新增主鍵的話,可以不用建,但因為oracle的主鍵生成方式和其他資料庫不一樣,所以只好建出來,其他資料庫有像increment的語法可用※Annotation設定
Person.java@Entity @Table public class Person { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "XXX") @SequenceGenerator(name = "XXX", sequenceName = "PERSON_SEQ") private Integer pid; private String pname; @OneToMany(mappedBy = "centerPerson", cascade = CascadeType.ALL) @LazyCollection(value = LazyCollectionOption.FALSE) private Set<PersonToilet> personToilets = new HashSet<>(); // setter/getter... }
Toilet.java
@Entity @Table public class Toilet { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "XXX") @SequenceGenerator(name = "XXX", sequenceName = "TOILET_SEQ") private Integer tid; private String tname; @OneToMany(mappedBy = "centerToilet", cascade = CascadeType.ALL) @LazyCollection(value = LazyCollectionOption.FALSE) private Set<PersonToilet> personToilets = new HashSet<>(); // setter/getter... }
PersonToilet.java
@Entity @Table(name = "PERSON_TOILET") public class PersonToilet { @Id @Column(name = "PT_ID") @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "XXX") @SequenceGenerator(name = "XXX", sequenceName = "PERSON_TOILET_SEQ") private Integer ptId; @ManyToOne(cascade = CascadeType.ALL) @JoinColumn(name = "PERSON_ID", unique = true) private Person centerPerson; @ManyToOne(cascade = CascadeType.ALL) @JoinColumn(name = "TOILET_ID", unique = true) private Toilet centerToilet; // setter/getter... }
※查詢時,中間表不需要@LazyToOne,只要在兩張表加@LazyCollection就可以查得到了
※刪除時,在資料庫有查到資料會將三張表全刪了,所以我將4個cascade拿掉才能刪,中間表也會刪,而CascadeType.REMOVE不等於整個拿掉,會出錯
沒有留言:
張貼留言