ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
# 1.3.3\. 使关联工作 我们把一些people和events 一起放到`EventManager`的新方法中: ``` private void addPersonToEvent(Long personId, Long eventId) { Session session = HibernateUtil.getSessionFactory().getCurrentSession(); session.beginTransaction(); Person aPerson = (Person) session.load(Person.class, personId); Event anEvent = (Event) session.load(Event.class, eventId); aPerson.getEvents().add(anEvent); session.getTransaction().commit(); } ``` 在加载一`Person`和`Event`后,使用普通的集合方法就可容易地修改我们定义的集合。如你所见,没有显式的`update()`或`save()`,Hibernate会自动检测到集合已经被修改并需要更新回数据库。这叫做自动脏检查(_automatic dirty checking_),你也可以尝试修改任何对象的name或者date属性,只要他们处于_持久化_状态,也就是被绑定到某个Hibernate 的`Session`上(如:他们刚刚在一个单元操作被加载或者保存),Hibernate监视任何改变并在后台隐式写的方式执行SQL。同步内存状态和数据库的过程,通常只在单元操作结束的时候发生,称此过程为清理缓存_(flushing)_。在我们的代码中,工作单元由数据库事务的提交(或者回滚)来结束——这是由`CurrentSessionContext`类的`thread`配置选项定义的。 当然,你也可以在不同的单元操作里面加载person和event。或在`Session`以外修改不是处在持久化(persistent)状态下的对象(如果该对象以前曾经被持久化,那么我们称这个状态为_脱管(detached)_)。你甚至可以在一个集合被脱管时修改它: ``` private void 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); session.getTransaction().commit(); // End of first unit of work aPerson.getEvents().add(anEvent); // aPerson (and its collection) is detached // Begin second unit of work Session session2 = HibernateUtil.getSessionFactory().getCurrentSession(); session2.beginTransaction(); session2.update(aPerson); // Reattachment of aPerson session2.getTransaction().commit(); } ``` 对`update`的调用使一个脱管对象重新持久化,你可以说它被绑定到一个新的单元操作上,所以在脱管状态下对它所做的任何修改都会被保存到数据库里。这也包括你对这个实体对象的集合所作的任何改动(增加/删除)。 这对我们当前的情形不是很有用,但它是非常重要的概念,你可以把它融入到你自己的应用程序设计中。在`EventManager`的main方法中添加一个新的动作,并从命令行运行它来完成我们所做的练习。如果你需要person及event的标识符 — 那就用`save()`方法返回它(你可能需要修改前面的一些方法来返回那个标识符): ``` else if (args[0].equals("addpersontoevent")) { Long eventId = mgr.createAndStoreEvent("My Event", new Date()); Long personId = mgr.createAndStorePerson("Foo", "Bar"); mgr.addPersonToEvent(personId, eventId); System.out.println("Added person " + personId + " to event " + eventId); } ``` 上面是个关于两个同等重要的实体类间关联的例子。像前面所提到的那样,在特定的模型中也存在其它的类和类型,这些类和类型通常是“次要的”。你已看到过其中的一些,像`int`或`String`。我们称这些类为_值类型(value type)_,它们的实例_依赖(depend)_在某个特定的实体上。这些类型的实例没有它们自己的标识(identity),也不能在实体间被共享(比如,两个person不能引用同一个`firstname`对象,即使他们有相同的first name)。当然,值类型并不仅仅在JDK中存在(事实上,在一个Hibernate应用程序中,所有的JDK类都被视为值类型),而且你也可以编写你自己的依赖类,例如`Address`,`MonetaryAmount`。 你也可以设计一个值类型的集合,这在概念上与引用其它实体的集合有很大的不同,但是在Java里面看起来几乎是一样的。