Hibernate 多对多关系详解(包括中间表,一对多字表)
Event事件表
Person 人员表
Person_Event 人员事件表
PersonEmailAddr邮件地址表
关系图:
事件对人员是多对多的关系,中间表Person_Event只有两个字段(PERSON_ID,EVENT_ID),邮件地址表只对应人员ID,一个人可以多个邮箱
*************** CLASS PERSON ***************
publicclass Person {
private Longid; //ID主键
privateintage; //属性
private Stringfirstname;//属性
private Stringlastname; //属性
private SetemailAddresses =new HashSet();//与表PersonEmailAddr对应字段的属性,邮件地址可以多个不同,所以放入Set中而不放入List中
private Setevents = new HashSet();//与表Person_Event对应字段的属性,道理跟上面一样
// Getter and Setter methods
// Defensive, convenience methods .由PERSON端维护关系,inverse=”false”
publicvoid addToEvent(Event event) {
this.getEvents().add(event);
event.getParticipants().add(this);
}
publicvoid removeFromEvent(Event event) {
this.getEvents().remove(event);
event.getParticipants().remove(this);
}
}
*************** CLASS EVENT ***************
publicclass Event {
private Longid; //主键ID
private Datedate; //属性
private Set<Person>participants =new HashSet<Person>(); //与表Person_Event对应字段的属性,道理跟上面一样
private Stringtitle; //属性
// Getter and Setter methods
}
******************* PERSON XML ******************
<hibernate-mapping>
<classname="events.Person"table="PERSON"> <!-- class.name指向类class.table指向表-->
<idname="id"column="PERSON_ID"> <!-- id.id指向属性 id.column指向字段-->
<generatorclass="native"/> <!-- 主键生成方法-->
</id>
<propertyname="age"/> <!-- property.name指向类的属性-->
<propertyname="firstname"/>
<propertyname="lastname"/>
<setname="events"table="PERSON_EVENT"><!-- set.name指向类的Set属性;set.table指向中间表名 inverse=”false” 由person端维护关系-->
<keycolumn="PERSON_ID"/><!-- key.column指出本类提供中间表的字段-->
<many-to-manycolumn="EVENT_ID"class="events.Event"/><!-- many-to-many.column指出另外的中间表的字段及刚才key的关系 many-to-many.class该字段对应的类名 -->
</set>
<setname="emailAddresses"table="PERSON_EMAIL_ADDR"><!-- set.name指向类的Set属性;set.table指向中间表名-->
<keycolumn="PERSON_ID"/><!-- key.column指出本类提供表的字段-->
<elementtype="string"column="EMAIL_ADDR"/><!-- element.column指出表的其他字段 element.type该字段的类型-->
</set>
</class>
</hibernate-mapping>
******************* EVENT XML ******************
<hibernate-mapping>
<classname="events.Event"table="EVENTS">
<idname="id"column="EVENT_ID">
<generatorclass="native"/>
</id>
<propertyname="date"type="timestamp"column="EVENT_DATE"/>
<propertyname="title"/>
<setname="participants"table="PERSON_EVENT"inverse="true">
<!-- inverse=”true” event不管关系由person端维护关系-->
<keycolumn="EVENT_ID"/>
<many-to-manycolumn="PERSON_ID"class="events.Person"/>
</set>
</class>
</hibernate-mapping>
******************* HIBERNATE CFG XML ******************
<session-factory>
<!-- Database connection settings -->
<propertyname="connection.driver_class">com.mysql.jdbc.Driver</property>
<propertyname="connection.url">jdbc:mysql:///test</property>
<propertyname="connection.username">root</property>
<propertyname="connection.password">root</property>
<!-- JDBC connection pool (use the built-in) -->
<propertyname="connection.pool_size">1</property>
<!-- SQL dialect -->
<propertyname="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- Enable Hibernate's automatic session context management -->
<propertyname="current_session_context_class">thread</property>
<!-- Disable the second-level cache -->
<propertyname="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<!-- Echo all executed SQL to stdout -->
<propertyname="show_sql">true</property>
<!-- Drop and re-create the database schema on startup -->
<propertyname="hbm2ddl.auto">create</property>
<mappingresource="events/Event.hbm.xml"/>
<mappingresource="events/Person.hbm.xml"/>
</session-factory>
******************** 测试类 ******************
publicclass EventManager {
publicstaticvoid main(String[] args) {
EventManager mgr = new EventManager();
// if (args[0].equals("createAndStoreEvent")) {
mgr.createAndStoreEvent("My Event",new Date());
//}
if (args[0].equals("listEvents")) {
List events = mgr.listEvents();
for (int i = 0; i < events.size(); i++) {
Event theEvent = (Event) events.get(i);
System.out.println("Event: " + theEvent.getTitle() +
" Time: " + theEvent.getDate());
}
}
elseif (args[0].equals("addpersontoevent")) {
//store event
Long eventId = mgr.createAndStoreEvent("My Event",new Date());
//store Person
Long personId = mgr.createAndStorePerson("Foo","Bar");
mgr.addPersonToEvent(personId, eventId);
System.out.println("Added person " + personId +" to event " + eventId);
}
elseif (args[0].equals("addemailtoperson")) {
Long personId = mgr.createAndStorePerson("Foozy","Beary");
mgr.addEmailToPerson(personId,"foo@bar");
// mgr.addEmailToPerson(personId, "bar@foo");
System.out.println("Added two email addresses (value typed objects) to person entity : " + personId);
}
HibernateUtil.getSessionFactory().close();
}
private Long createAndStoreEvent(String title, Date theDate) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
//theEvent is transient
Event theEvent = new Event();
theEvent.setTitle(title);
theEvent.setDate(theDate);
//theEvent turns to persistent
session.save(theEvent);
session.getTransaction().commit();
return theEvent.getId();
}
private Long createAndStorePerson(String firstname, String lastname) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
Person thePerson = new Person();
thePerson.setFirstname(firstname);
thePerson.setLastname(lastname);
session.save(thePerson);
session.getTransaction().commit();
return thePerson.getId();
}
private List listEvents() {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
List result = session.createQuery("from Event").list();
session.getTransaction().commit();
return result;
}
privatevoid addPersonToEvent(Long personId, Long eventId) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
Person aPerson = (Person) session
.createQuery("select p from Person p left join fetch p.events where p.id = :pid")
.setParameter("pid", personId)
.uniqueResult();// Eager fetch the collection so we can use it detached
/*
Event anEvent = (Event) session.load(Event.class, eventId);
*/
// If we want to handle it bidirectional and detached, we also need to load this
// collection with an eager outer-join fetch, this time with Criteria and not HQL:
Event anEvent = (Event) session
.createCriteria(Event.class).setFetchMode("participants", FetchMode.JOIN)
.add( Expression.eq("id", eventId) )
.uniqueResult();// Eager fetch the colleciton so we can use it detached
System.out.println("session.getTransaction().commit();");
session.getTransaction().commit();
// End of first unit of work
aPerson.getEvents().add(anEvent);// aPerson is detached
// or bidirectional safety method, setting both sides: aPerson.addToEvent(anEvent);
// Begin second unit of work
Session session2 = HibernateUtil.getSessionFactory().getCurrentSession();
session2.beginTransaction();
session2.update(aPerson);// Reattachment of aPerson
System.out.println("session2.getTransaction().commit();");
session2.getTransaction().commit();
}
privatevoid addEmailToPerson(Long personId, String emailAddress) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
Person aPerson = (Person) session.load(Person.class, personId);
// The getEmailAddresses() might trigger a lazy load of the collection
aPerson.getEmailAddresses().add(emailAddress);
session.getTransaction().commit();
}
}
本文来源官方文档:hibernate3.2.5