EJB persistence(三)

ZDNet软件频道 时间:2006-05-10 作者:DJ Walker-Morgan |  我要评论()
本文关键词:
在前几部分里,我们已经讨论过了Java SE的JPA的基本保持元素。在本文里,我们将看一个示例应用程序,并详细讨论如何在你的开发中应用JPA。
无标题文档

这里没有什么特别值得注意的;populateApplications方法用来取回所有的应用程序,填充用于显示列表的用户界面模型,然后我们在这个列表里选择刚刚保持的Application。现在让我们向Application加入一个Version。这里,currentApplication是当前选择的Application的实例,它用新版本名字字符串来命名:

void addVersion(String versionname) {
if(currentApplication==null) return;
Version ver=new Version();
ver.setVersionname(versionname);
ver.setApplication(currentApplication);
currentApplication.getVersions().add(ver);
licmanStore.updateApplication(currentApplication);
populateVersions();
ui.setSelectedVersion(ver);
}

我们要做的是创建一个新的Version,设置它的名称,将它的父类设置为currentApplication,然后把版本添加到currentApplication的版本列表里。要对数据库进行这些操作,我们要做的是更新/合并currentApplication。但是这段代码有一个问题;刚刚创建的版本没有在列表里被选中。如果实体管理程序已经接管了层叠,那么我们新添加的Version实例就无法被托管,它只是一个外壳,这与我们把Application保存在addApplication()里的时候对象明确地变成可托管的不一样。这里的代码不起作用,因为当我们试着在方法结束时在列表里选择版本的时候,列表里没有我们开始时使用的Version外壳,只有另外一个基于它的可托管Version实例。解决方案很简单,只用取回可托管的版本就行了。已有的getVersion方法会处理取回操作:

Version getVersion(Application app,String name) {
try {
    Query q=em.createQuery("select ver from Version as ver
      where application=:app and versionname=:name");
    q.setParameter("app",app);
    q.setParameter("name",name);
    return (Version)q.getSingleResult();
  } catch (NoResultException nre) {
     return null; }
}

Query的getSingleResult方法只返回一个结果,在发现没有结果或者有多个结果的时候,它会引发异常。在这里,我们把没有返回结果解释为返回为“空”。现在我们可以更改Controller的addVersion方法来使用它,此外我们还可以用它来检查我们没有创建重复的名称,当我们真的重复创建了名称的时候它就引发异常:

void addVersion(String versionname) throws UpdateException {
if(currentApplication==null) return;
if(licmanStore.getVersion(currentApplication,
    versionname) != null)
      throw new UpdateException("Version "
        + versionname + " already exists");
...
populateVersions();
ver=licmanStore.getVersion(currentApplication,versionname);
ui.setSelectedVersion(ver);
}

现在,刚刚创建的版本会被自动地选中。作为对读者的一种练习,我们在创建Licence的代码中留了一个类似的错误供修复。

在使用已扩展的persistence上下文时需要记住的一件事是,你确实需要让保持实体同步。有两种方式可以做到这一点。例如,当我们把User指派给Licence的时候,我们必须要记住更新内存里User的许可证集合,并把User添加到Licence的用户集合里。在Controller的addUsersToLicence方法里,我们保证增加了User和Licence列表:

void addUsersToLicence(List<User> u) throws UpdateException {
if(currentLicence==null) throw
    new UpdateException("No licence selected");
currentLicence.getUsers().addAll(u);
for(User ut:u) ut.getLicences().add(currentLicence);
licmanStore.updateApplication(currentApplication);
populateLicenceUsers();
}

当然这样做有可能不现实;另外一种方式是让实体管理程序来刷新可托管对象,让其与数据库进行同步。要这样做我们要向LicManStore加入一个refresh方法:

void refresh(Object o) { em.refresh(o); }

只刷新来自数据库的User实例:

void addUsersToLicence(List<User> u) throws UpdateException {
if(currentLicence==null) throw
    new UpdateException("No licence selected");
currentLicence.getUsers().addAll(u);
licmanStore.updateApplication(currentApplication);
for(User ut:u) licmanStore.refresh(ut);
populateLicenceUsers();
}

如果我们不得不对实体管理器使用默认的事务处理上下文,那么实体管理器往往是新创建的,我们就不会有残留的、还未从数据库刷新的可托管对象。

最后,让我们来看看列出了一个用户所拥有的所有许可证的“许可证报告(Licence report)”;它会在你双击用户列表上的某个用户时显示。这完全是通过整理(元素之间的)关系,利用从Licences的User类列表里取得的应用程序的名称和版本名称而获得的。

...
StringBuilder sb=new StringBuilder();

for(Licence l:user.getLicences()) {
    sb.append(l.getVersion().getApplication().getApplicationname());
    sb.append(" ");
    sb.append(l.getVersion().getVersionname());
    sb.append(" ");
    sb.append(l.getLicenceKey());
    sb.append(" ");
} ...

这里没有对数据库进行直接的访问,因为实体管理程序负责在Licence、Version和Application类被访问的时候调用它们,这要感谢已扩展的persistence上下文。这当然是要付出代价的,尤其是在应用程序为被访问的对象提供缓冲的过程中内存的使用,这就是为什么在计划如何使用JPA的时候你总应该考虑使用事务处理上下文并根据需要创建实体管理程序。

本文把重点放在了在Java Standard Edition里使用JPA上。JPA不是只能用于Java SE,它根植于Java Enterprise Edition。我们在这里使用的类同样可以不加任何改变就用在企业应用程序里;真正的变化在于你如何取得实体管理程序,以及在哪里取得它的配置。体系结构的可移植性是JPA的真正亮点。在Java SE上学到的技术也可以移植到Java EE上。

你可以在这里下载本文所涉及的源代码。

DJ Walker-Morgan是一名开发咨询师,专长是Java和用户到用户的消息发送和视频会议。

责任编辑:张琎

查看本文的国际来源


百度大联盟认证黄金会员Copyright© 1997- CNET Networks 版权所有。 ZDNet 是CNET Networks公司注册服务商标。
中华人民共和国电信与信息服务业务经营许可证编号:京ICP证010391号 京ICP备09041801号-159
京公网安备:1101082134