现在的位置: 首页 > 综合 > 正文

在Eclipse中使用Hibernate插件 *******生成代码

2013年08月23日 ⁄ 综合 ⁄ 共 6181字 ⁄ 字号 评论关闭
生成代码

  这很可能是您一直期待的部分。我们可以做些什么特别的呢?马上就有一个可用于Hibernate映射文档的新上下文菜单项。

  如果右击(或控制单击)任意一项,将会看到很多与Hibernate相关的选项(图17),其中包括一个同步选项。这是一种手动让Hibernate Synchronizer生成与映射文档相关的数据访问对象的方式。

Figure 17
图17.映射文档的同步选项

  Add Mapping Reference选项也很有用:它在主Hibernate配置文件中添加了一项,告知有关该映射文档的信息,所以无需在源代码中加入任何内容来要求配置相应的映射。现在我们来看看选择Synchronize Files的结果。

  到这里事情开始变得有趣了。出现了两个新的子包,一个用于Hibernate Synchronizer“拥有的”“基”数据访问对象,可以在任何时候进行改写,而另一个用于为这些DAO生成子类的业务对象,它不会被重写,这为我们提供了一个向数据类添加业务逻辑的机会(如图18所示)。

Figure 18
图18. 经过同步的数据访问对象,显示了可编辑的子类

  这样生成的类比使用常规的Hibernate代码生成工具生成的类要多很多,这有一些优点以及一些潜在的缺点,在稍后的权衡部分中我们将讨论这些。还要注意,可以在项目的属性配置中选择生成其中的哪些类,以及生成它们的包结构。我本来应该演示一下的,但是当前的插件版本有一个bug,它阻止了在Mac OS X上对这个配置界面进行访问。补丁已经开发出来了,但尚未发布。

  基于Hibernate Synchronizer页面上的例子与下面的类,我试图使用这些新的数据访问对象插入一些数据到音乐数据库中。这十分类似于使用标准Hibernate代码生成器的版本(在Hibernate: A Developer's Notebook一书的39-40页),甚至更为简单,因为Hibernate Synchronizer生成的类针对每项数据库操作都创建并提交了一个新事务,所以在像这样简单的场境中,您不需要编写代码来设置事务。(当然了,要让一组操作作为单个事务运行,有很多种方法。)下面是新版本的代码:

package com.oreilly.hh;

import java.sql.Time;
import java.util.Date;
import net.sf.hibernate.HibernateException;
import com.oreilly.hh.dao.TrackDAO;
import com.oreilly.hh.dao._RootDAO;

/**
 * Try creating some data using the Hibernate Synchronizer approach.
 */
public class CreateTest2 {

    public static void main(String[] args) throws HibernateException {
        // Load the configuration file
        _RootDAO.initialize();
        
        // Create some sample data
        TrackDAO dao = new TrackDAO();
        Track track = new Track("Russian Trance", "vol2/album610/track02.mp3",
            Time.valueOf("00:03:30"), new Date(), (short)0);
        dao.save(track);
        
        track = new Track("Video Killed the Radio Star",
            "vol2/album611/track12.mp3", Time.valueOf("00:03:49"), new Date(),
            (short)0);
        dao.save(track);
        
        // We don't even need a track variable, of course:
        dao.save(new Track("Gravity's Angel", "/vol2/album175/track03.mp3",
            Time.valueOf("00:06:06"), new Date(), (short)0));
    }
}

  当我编写这些代码时,可以使用Eclipse是一件十分惬意的事情。我已经忘了当我为书籍编写例子时,我多么希望可以使用智能代码完成功能,而且JDT在其他方面也同样能帮上忙。

  为了在Eclipse中运行这个简单的程序,我们需要设置一个新的Run配置。选择Run -> Run...,把CreateTest2.java作为当前的活动编辑器文件。单击New,Eclipse就会知道我们想要在当前项目中运行这个类,因为我们使用main()方法创建它。它指定的默认名称是CreateTest2。界面应该如图19所示。单击Run,试着创建一些数据。

Figure 19
图19.准备好在Eclipse中运行我们的创建测试

  如果您确实遵照了这些步骤,您就会发现执行时首次尝试将会失败:Hibernate抱怨说配置文件没有包含映射引用,而按要求至少要有一个。啊哈!所以,这就是图16底部XMLBuddy出现黄色下划线警告的原因。我们可以很容易地解决这个问题,具体方法是在Package Explorer视图中的Track.hbm.xml映射文档上右击,然后在新的Hibernate Synchronizer子菜单中选择Add Mapping Reference。这对XMLBuddy来说是正确的做法,可以让运行继续。遗憾的是,运行没有继续多久。下一个错误是无法在JNDI中找到JTA UserTransaction初始上下文。显然我并非惟一遇到这种问题的人,在一个论坛主题中相关的讨论如火如荼,但是还没有人找到解决方案。

  因为知道我不需要使用JTA,所以我想知道为什么Hibernate要尝试找到JTA。我打开了Hibernate配置文件(图16),然后寻找Hibernate Synchronizer中的任何可疑之处。无疑有几行是最有嫌疑的:

<property name="hibernate.transaction.factory_class"> 
       net.sf.hibernate.transaction.JTATransactionFactory 
 </property> 
 <property name="jta.UserTransaction"> 
       java:comp/UserTransaction 
 </property> 

  我试着把上述内容注释掉并再次运行,这第三次运行成功了。运行没有出现错误,我的数据出现在数据库中。哇!运行可以信赖的antdb目标(Developer's Notebook一书的第1章中对此有说明)便可以看到所有数据(确实很简单),如图20所示。如果您要这样做,要确保从一个antschema开始创建数据库模式,或者清空来自前面实验中的任何测试数据。

Figure 20
图20.测试程序所创建的数据

  注意,可以在Eclipse中运行Ant目标,具体方法是右击(或控制单击)Package Explorer中的build.xml文件,选择Run An,然后使用Eclipse对话框选择目标。酷吧?

Figure 21
图21.在Eclipse中运行Ant

  使用查询取回数据相当简单,尽管这次的代码很接近于常规的使用Hibernate生成的普通数据访问类所使用的代码。即使Hibernate Synchronizer为处理指定查询生成了大量帮助器方法,我还是认为它们中间没有哪一个方法特别有用,因为它们都坚持运行查询后返回结果列表,而不是提供可以直接使用的Query对象。这使您无法使用Query的方便的类型安全的参数设置方法。因为这一点,我决定一定要让RootDAO对象为我提供一个Hibernate Session,以便使用老式的方法。我认为我可以编辑Hibernate Synchronizer使用的任何模板来生成我想要的任何方法,如果我要使用它来开发一个项目,我几乎肯定我会这么做。

  实际上,进一步考虑的话,因为当获得一个活动的Session时,您只能处理Query,DAO所提供的方法已经达到了最佳效果。如果您想像我在这个例子中所做的那样处理查询,您必须总是自己进行会话管理。可以把会话管理嵌入到“您自己的”那一半DAO所提供的业务逻辑中,这就可以同时利用两方面的好处了。这正是Hibernate Synchronizer提供的拆分类模型如此有用的另一个原因。我将在下面对此进行深入探讨。

  不管怎样,下面是我第一次想出的代码,基本上等同于书中48-49页上给出的代码:

package com.oreilly.hh;

import java.sql.Time;
import java.util.ListIterator;

import net.sf.hibernate.HibernateException;
import net.sf.hibernate.Query;
import net.sf.hibernate.Session;

import com.oreilly.hh.dao.TrackDAO;
import com.oreilly.hh.dao._RootDAO;

/**
 * Use Hibernate Synchronizer's DAOs to run a query
 */
public class QueryTest3 {

    public static void main(String[] args) throws HibernateException {
        // Load the configuration file and get a session
        _RootDAO.initialize();
        Session session = _RootDAO.createSession();

        try {
            // Print the tracks that will fit in five minutes
            Query query = session.getNamedQuery(
                TrackDAO.QUERY_COM_OREILLY_HH_TRACKS_NO_LONGER_THAN);
            query.setTime("length", Time.valueOf("00:05:00"));
            for (ListIterator iter = query.list().listIterator() ;
                 iter.hasNext() ; ) {
                Track aTrack = (Track)iter.next();
                System.out.println("Track: /"" + aTrack.getTitle() +
                                   "/", " + aTrack.getPlayTime());
            }
        } finally {
            // No matter what, close the session
            session.close();
        }
    }
}

  TrackDAO提供的一个优秀特性是静态常量,通过它,我们可以请求指定查询,消除任何由于字符串输入错误而引起运行时错误的可能性。我喜欢这一点!为这个测试类设置和执行Run配置,将会生成预期的输出,如图22所示。

Figure 22
图22. Eclipse控制台视图中的查询结果

  我前面提到过,运行这个类之后,我意识到,借助于Hibernate Synchronizer所提供的模型,可以用一种更好的方法来实现它。因为指定查询是与该数据访问对象相关的映射文件的一项特性,所以如果我们将查询放入TrackDAO对象中(这才是它真正属于的地方),那么这个对象看起来应该是下面这个样子:

package com.oreilly.hh.dao;

import java.sql.Time;
import java.util.List;

import net.sf.hibernate.HibernateException;
import net.sf.hibernate.Query;
import net.sf.hibernate.Session;

import com.oreilly.hh.base.BaseTrackDAO;

/**
 * This class has been automatically generated by Hibernate Synchronizer.
 * For more information or documentation, visit The Hibernate Synchronizer page
 * at http://www.binamics.com/hibernatesync or contact Joe Hudson at joe@binamics.com.
 *
 * This is the object class that relates to the TRACK table.
 * Any customizations belong here.
 */
public class TrackDAO extends BaseTrackDAO {

    // Return the tracks that fit within a particular length of time
    public static List getTracksNoLongerThan(Time time)
        throws HibernateException
    {
        Session session = _RootDAO.createSession();
        try {
            // Print the tracks that will fit in five minutes
            Query query = session.getNamedQuery(
                QUERY_COM_OREILLY_HH_TRACKS_NO_LONGER_THAN);
            query.setTime("length", time);
            return query.list();
        } finally {
            // No matter what, close the session
            session.close();
        }
    }
}

  这样做更好更清晰,还进一步简化了QueryTest3中的main()方法:

    public static void main(String[] args) throws HibernateException {
        // Load the configuration file and get a session
        _RootDAO.initialize();

        // Print the tracks that fit in five minutes
        List tracks = TrackDAO.getTracksNoLongerThan(Time.valueOf("00:05:00"));
        for (ListIterator iter = tracks.listIterator() ;
             iter.hasNext() ; ) {
            Track aTrack = (Track)iter.next();
            System.out.println("Track: /"" + aTrack.getTitle() +
                               "/", " + aTrack.getPlayTime());
        }
    }

  显然,这是一种在使用Hibernate Synchronizer时处理指定查询的方法。做一次快速测试就可以确认它生成同样的输出,而且它的代码也要好很多。

  您是否想使用Hibernate Synchronizer来生成它自己的数据访问对象类型暂且放下,我们还有最后一项重要特性要探讨。

抱歉!评论已关闭.