论坛首页 Java企业应用论坛

EJB3.0中的实体Bean在事件回调方法中得到EntityManager

浏览 3258 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2008-02-12  
图书管理系统的一个需求:需要对图书进行分类,分类之间有隶属关系,这样所有的分类就形成了一棵“分类树”。为了快速地找到某个分类下的所有子分类(包括孙子,曾孙分类),
每个分类需要保存一个序列号,这个序列号反应了本分类在分类树中的位置。举个例子,有如下四个分类“食物,水果,肉类,香蕉”,其中,香蕉属于水果,水果属于食物,肉类也属于食物。构成的分类树是这样的

食物--水果--香蕉
   |--肉类

可以这样分配序列号(每一代分类用两位数字表示,可以根据需要用更多或更少的位数):
食物(00)--水果(0000)--香蕉(000000)
         |--肉类(0001)

每个分类都继承父分类的序列号,在加上两位的按递增的序号。如果要找到食物的所有子分类,就可以用 类似“from 分类表 where 序列号 like 00%”的sql语句快速找到。
这种设计方法也可以适用于其他有树结构的领域模型,如组织机构。
用EJB3.0的实体Bean来实现这个模型基本上是很简单,详细的代码就不列出来。比较麻烦的是这个序列号字段不能使用数据库提供的序列号生成器来生成,必须得我们自己来生成。生成序列号的步骤:
1,得到父分类的序列号supercsn
2,根据supercsn到数据库中查找兄弟分类的最大序列号maxcsn
3,把maxcsn的最后两位的数字加一,作为本分类的序列号。

生成序列号的最好时机就是在实体bean的PrePersist事件中,也就需要在PrePersist事件中访问数据库。这时,你是不是很自然得想到用这样的代码得到EntityManager:
@Entity
public class Category implements Serializable {
@PersistenceContext
  EntityManager em;
..........
}
当时,很不幸的是:这样得不到EntityManager,每次都是Null.(如果哪位大哥能这样获得的,请告诉我一下)。经过查询Jboss的文档,发现了另外一个变通的办法。Jboss可以把EntityManagerFactory保存到jndi中去,因此就可以从jndi查找出EntityManagerFacotry来,再用它来创建出EntityManager来。
为了达到上述目的,需要修改EJB工程的Persistence.xml文件
	<persistence-unit name="BookStorePU" transaction-type="JTA">
		<jta-data-source>java:bookshopDS</jta-data-source>
		<properties>
			<property name="hibernate.hbm2ddl.auto" value="update" />
			<property name="hibernate.show_sql" value="true" />
<!--将entity manager factory 绑定到 java:/BookStorePUEMF-->
			<property name="jboss.entity.manager.factory.jndi.name"
				value="java:/BookStorePUEMF" />
		</properties>
	</persistence-unit>


在实体bean中就可以得到EntityManagerFactory了。
   @PrePersist
	public void setUpCSN() {
	   log.info("Persist "+getCname()+" begin");
		String supercsn = "";
		String mycsn="";
        Properties env=new Properties();
		if (this.getSuperCategory() != null) {
			supercsn = getSuperCategory().getCsn();
			log.info("super category "+getSuperCategory().getCname()+" CSN:"+supercsn);
		}
		if (supercsn==null){
			supercsn="";
		}
		EntityManager em=null;
		EntityManagerFactory emf=null;
		int csnlen = supercsn.length()+Consts.CATEGORY_CSN_LEVELLENTH;
		try {
			env.load(getClass().getResourceAsStream("/jndi.properties"));
			Context ctx= new InitialContext(env);
			Object o=ctx.lookup("java:/BookStoreEM");
			emf=(EntityManagerFactory)o;
			em=emf.createEntityManager();
			String eql="select max(c.csn) as m from Category c where length(c.csn)="+csnlen+" and c.csn like'"+supercsn+"%'";
			Query qry=em.createQuery(eql);
			List rstList=qry.getResultList();
			String maxcsn=(String) rstList.get(0);
			log.info(getCname()+" maxcsn:"+maxcsn);
			if (maxcsn==null){
				mycsn=supercsn+supplyZero(Consts.CATEGORY_CSN_LEVELLENTH);
			}else{
    			mycsn=genNextCSN(maxcsn,csnlen);
			}
			this.setCsn(mycsn);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}finally{
			em.close();
			
		}
		//log.info("Persist "+getCname()+" begin."); 
	}


补充一下,需要在类路径下放一个jndi.properties的文件,以保证能够访问到应用服务器的jndi

   发表时间:2008-10-06  
看不出有什么好处,
也看不出有什么亮点。

操作的流程都一样的,数据库连接等等操作都是一样的,又没有减少。
只是把操作的“时机”放在了不同的地方。
楼主不觉得多此一举吗?
0 请登录后投票
   发表时间:2008-10-06  
以上纯属讨论。绝非攻击。

jfan
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics