使用 EJB 数据介体服务来访问数据
下列步骤使用代码样本来描述有关如何创建 Enterprise JavaBeans (EJB) 数据介体服务 (DMS) 元数据的简单实例。
过程
示例
- 将查询自变量与 EJB 介体配合使用。
以下示例显示如何能够调整您的 Enterprise JavaBeans (EJB) 介体查询自变量。
- 简单示例
- 该查询返回包含多个实例的类型(Eclass 名称)为 Emp 的 DataObject 的 Datagraph。数据对象属性是 empid 和 name,并且它们的数据类型对应于容器管理的持久性 (CMP) 字段类型。
按如下所示已返回的 DataGraph 按其 XML 格式序列化:select e.empid, e.name from Emp as e where e.salary > 100
<?xml version="1.0" encoding="ASCII"?> <datagraph:DataGraphSchema xmlns:datagraph="datagraph.ecore"> <root> <Emp empid="1003" name="Eric" /> <Emp empid="1004" name="Dave" /> </root> </datagraph:DataGraphSchema>
- 查询参数
- 此示例显示了如何使用参数标记。重新调用 EJB 查询中参数标记的语法,会有问号后跟有数字的标记(?n)。在 EJB 介体上调用 getGraph ( ) 方法时,您可以可选地传递值的数组。?n 是指值 parm[n-1]。还可以在工厂调用上传递值的数组来创建 EJB 介体。getGraph( ) 上传递的参数覆盖 create 调用上传递的任何参数。
select e.empid, e.name from Emp as e where e.salary > ?1
- 返回表达式和方法
- 该示例描述可以是查询表达式的返回值的数据对象属性。EJB 查询表达式包括算术、日期时间、路径表达式和方法。输入自变量和方法的返回值限制为该列表中的支持数据类型(请参阅“EJB 介体查询语法”主题)。处理 applyChanges 期间,包含从表达式派生的更新属性的数据对象导致发生异常,除非用户提供了用于处理更改的介体适配器。
数据对象属性名称是从 CMP 字段名派生的,但是可以使用查询中的 AS 关键字重设这些属性名称。当指定表达式时,应该总是使用 AS 关键字为该表达式给定一个名称。select e.empid as employeeId, e.bonus+e.salary as totalPay, e.dept.mgr.name as managerNam, e.computePension( ) as pension from Emp as e where e.salary > 100
- * 语法
- 表示法 e.* 是一种指定 EJB 的所有 CMP 字段(但不是容器管理的关系)的简单快捷方法。以下查询与 e.empid, e.name e.salary, e.bonus 的作用相同。
select e.* from Emp as e
- select 子句中没有主键
- 该示例显示不返回主键字段的查询。然而,除非数据对象包含 EJB 的所有主键字段,否则介体无法处理对 DataGraph 的更新。这是因为需要主键将更改转换为结构化查询语言 (SQL)、或者将 DataObject 引用转换为 EJB 引用。当尝试运行 applyChanges 时发生异常。
select e.name, e.salary from Emp as e
- Order by
- 可以对 DataObject 进行排序。
这导致按名称对 Dept 对象进行排序,以及按 empid 对每个 Dept 中的 Emp 对象以降序排序。select d.* from Dept d order by d.name select e.* from in(d.emps) e order by e.empid desc
- 浏览多值的关系
- 此复合查询返回具有 DataObject 类 Dept 和 Emp 的 Datagraph。Datagraph 的形状影响 FROM 子句中使用的路径表达式。
在此事例中,Dept 是 Datagraph 中的根节点,并且存在从 Dept 到 Emp 的多值引用,如下所示:select d.deptno, d.name, d.budget from Dept d where d.deptno < 10 select e.empid, e.name, e.salary from in(d.emps) e where e.salary > 10
<?xml version="1.0" encoding="ASCII" ?> <datagraph:DataGraphSchema xmlns:datagraph="datagraph.ecore"> <root> <Dept deptno="1" name="WAS_Sales" budget="500.0" emps="//@root/@Emp.1 //@root/@Emp.0" /> <Dept deptno="2" name="WBI_Sales" budget="450.0" emps="//@root/@Emp.3 //@root/@Emp.2" /> <Emp empid="1001" name="Rob" salary="100.0" EmpDept="//@root/@Dept.0" /> <Emp empid="1002" name="Jason" salary="100.0" EmpDept="//@root/@Dept.0" /> <Emp empid="1003" name="Eric" salary="200.0" EmpDept="//@root/@Dept.1" /> <Emp empid="1004" name="Dave" salary="500.0" EmpDept="//@root/@Dept.1" /> </root> </datagraph:DataGraphSchema>
- 有关查询参数的更多信息
- 可以在任何查询上指定搜索条件。对于查询而言输入自变量是全局的,并且可以在复合查询的任何位置用数字引用这些参数。在上述示例中,create 或 getGraph 调用中传递的查询自变量应该按 { deptno value, salary value, deptno value } 顺序传递。
select d.* from Dept as d where d.deptno between ?1 and ?3 select e.* from in(d.emps) e where e.salary < ?2
- 浏览具有多个关系的路径
- 以下查询浏览由 EJB 关系 Dept.projs 和 Project.tasks 组成的路径,并返回包含所选 CMP 字段的 Dept、Emp 和 Project 的 DataObject。
此处显示了得出的 XML 格式的 DataGraph。select d.deptno, d.name from Dept as d select p.projid from in(d.projects) p select t.taskid, t.cost from in (p.tasks) t
<?xml version="1.0" encoding="ASCII" ?> <datagraph:DataGraphSchema xmlns:datagraph="datagraph.ecore"> <root> <Dept deptno="1" name="WAS_Sales" projects="//@root/@Project.0" /> <Dept deptno="2" name="WBI_Sales" projects="//@root/@Project.1" /> <Project projid="1" ProjectDept="//@root/@Dept.0" tasks="//@root/@Task.0 //@root/@Task.2 //@root/@Task.1" /> <Project projid="2" ProjectDept="//@root/@Dept.1" tasks="//@root/@Task.3" /> <Task taskid="1" cost="50.0" TaskProject="//@root/@Project.0" /> <Task taskid="2" cost="60.0" TaskProject="//@root/@Project.0" /> <Task taskid="3" cost="900.0" TaskProject="//@root/@Project.0" /> <Task taskid="7" cost="20.0" TaskProject="//@root/@Project.1" /> </root> </datagraph:DataGraphSchema>
- 浏览多个路径
- 此处是返回具有相关职员的 Dept 的 DataObject 的 DataGraph 的介体查询,以及检索相关项目和任务的第二个路径。
返回的 DataGraph 看起来为如下所示:select d.deptno, d.name from Dept d select e.empid, e.name from in(d.emps) e select p.projid from in(d.projects) p select t.taskid, t.cost from in(p.tasks) where t.cost > 10
<?xml version="1.0" encoding="ASCII" ?> <datagraph:DataGraphSchema xmlns:datagraph="datagraph.ecore"> <root> <Dept deptno="1" name="WAS_Sales" projects="//@root/@Project.0" emps="//@root/@Emp.1 //@root/@Emp.0" /> <Dept deptno="2" name="WBI_Sales" projects="//@root/@Project.1" emps="//@root/@Emp.3 //@root/@Emp.2" /> <Project projid="1" ProjectDept = "//@root/@Dept.0" tasks="//@root/@Task.0 //@root/@Task.2 //@root/@Task.1" /> <Project projid="2" ProjectDept="//@root/@Dept.1" tasks="//@root/@Task.3" /> <Task taskid="1" cost="50.0" TaskProject="//@root/@Project.0" /> <Task taskid="2" cost="60.0" TaskProject="//@root/@Project.0" /> <Task taskid="3" cost="900.0" TaskProject="//@root/@Project.0" /> <Task taskid="7" cost="20.0" TaskProject="//@root/@Project.1" /> <Emp empid="1001" name="Rob" EmpDept="//@root/@Dept.0" /> <Emp empid="1002" name="Jason" EmpDept="//@root/@Dept.0" /> <Emp empid="1003" name="Eric" EmpDept="//@root/@Dept.1" /> <Emp empid="1004" name="Dave" EmpDept="//@root/@Dept.1" /> </root> </datagraph:DataGraphSchema>
- 浏览单值的关系
- 这里要指出的重要信息是即使 Emp 是图中的根数据对象,多个 Emp 数据对象也将与同一 Dept 数据对象相关。因此,与先前示例不同,当您查看数据对象实例时,数据图不是树形图;有多个根 Emp 对象与同一 Dept 对象相关。但是此时它毕竟是一个数据图,而不是数据树。注意,介体查询允许 FROM 子句中有单值路径表达式。这是标准 EJB 查询语法的更改。
而 XML 格式的 DataGraph 按如下所示:select e.empid, e.name from Emp e select d.deptno, d.name from in(e.dept) d
<?xml version="1.0" encoding="ASCII" ?> <datagraph:DataGraphSchema xmlns:datagraph="datagraph.ecore"> <root> <Emp empid="1001" name="Rob" dept="//@root/@Dept.0" /> <Emp empid="1002" name="Jason" dept="//@root/@Dept.0" /> <Emp empid="1003" name="Eric" dept="//@root/@Dept.1" /> <Emp empid="1004" name="Dave" dept="//@root/@Dept.1" /> <Dept deptno="1" name="WAS_Sales" DeptEmp="//@root/@Emp.1 //@root/@Emp.0" /> <Dept deptno="2" name="WBI_Sales" DeptEmp="//@root/@Emp.3 //@root/@Emp.2" /> </root> </datagraph:DataGraphSchema>
- SELECT 子句中的路径表达式
- 此查询与先前描述的查询相似(两种查询都返回职员数据以及部门号和名称),但是注意,数据图只包含该查询中的一个数据对象类型(与先前相比,在先前的查询中包含两个数据对象类型)。字段 deptno 和 name 字段是只读的,这是因为它们是由 SELECT 子句的路径表达式生成的并且不是 Emp EJB 的 CMP 字段。
select e.empid as EmplId , e.name as EmpName , e.dept.deptno as DeptNo , e.dept.name as DeptName from Emp as e
- 浏览多对多关系
- Emp 与 Task 之间的关系被认为是多对多关系。以下查询将检索职员、任务和项目。DataGraph 中的任何特定任务 DataObject 都将只出现一次,尽管它可能与许多职员相关。
select e.empid, e.name from Emp as e select t.taskid, t.description from in(e.tasks) as t select p.projid, p.cost from in(t.proj) as p
- 数据对象之间的多个链接
- EJB 介体使您可以根据关系来检索数据,并使用 XREL 命令来根据已经检索的数据来构造一个或多个附加关系。介体还允许根据 ASNname 来检索数据,然后使用 XREL 命令并根据已检索的数据来构造一个或多个关系。以下查询将检索各个部门、在各个部门工作的职员以及负责管理各个部门的职员。
第二个和第三个 select 子句都将返回 Emp DataObject 的实例。通过 d.emps 关系和 d.manager 关系有可能检索到同一 Emp 实例。这种情况下,EJB 介体将只创建一个 Emp 实例,但是将同时创建这两种关系。select d.deptno, d.name from Dept d where d.name like ‘%Dev%' select e.empid, e.name from in (d.emps) as e select m.empid, m.name from in(d.manager) as m
以下查询将按如下所示进行处理。将根据第一个查询中的数据来创建 Dept DataObject。将根据第二个查询中的数据来创建 Emp DataObject。然后,会为 FROM 子句或 XREL 关键字中使用的任何关系构造图中的关系。在构造关系期间,不会检索其他数据。在此示例中,一个在 Dev 部门工作的职员将出现在 DataGraph 中。如果此职员负责管理 Sales 部门,那么 manages 引用为空。在第一个查询中将检索 Dev 部门,而不是 Sales 部门。select d.deptno, d.name from Dept d where d.name like ‘%Dev%' select e.empid, e.name from in (d.emps) as e xrel d.manager
emps 和 manager 关系是根据从这些查询中创建的 DataObject 实例来构造的。名为“Dev”但是在“Sales”部门工作的员工在图中将具有空的 dept 关系。select d.deptno, d.name from Dept d where d.name like ‘%Dev%' select e.empid, e.name from Emp e where e.name like ‘Dev%' xrel d.emps, d.manager
下一个示例显示为给定部门的所有职员、项目和任务检索数据对象,还显示职员与任务之间的链接。select d.deptno from Dept d where d.deptno = 42 select e.empid from in(d.emps) e select p.projid from in(d.projs) p select t.* from in(p.tasks) t xrel e.tasks
如果将一项任务分配给 42 部门中的一个职员,那么该链接将出现在数据图中。如果将该任务分配给一个不属于 42 部门的职员,那么该链接不会出现在数据图中。这是因为该数据对象被查询过滤掉了。XREL 关键字后面可以跟一个或多个 EJB 关系。双向关系可以表示任一角色名称。必须通过一个或多个查询来检索关系的源和目标。
- 检索不相关的对象
- 以下查询将检索 Dept 和 Task。
select d.deptno, d.name from Dept d where d.name like ‘%Dev%' select t.taskid, t.startDate from Task t where t.startDate > ‘2005'
以下查询将检索 Dept 和 Emp。尽管 Dept 与 Emp 之间存在一些关系(即,mgr 和 emps),但是在 FROM 或 XREL 中不会使用任何一种关系,因此,获得的图中不包含关系值。select d.deptno, d.name from Dept d where d.name like ‘%Dev%' select e.empid, e.name from Emp e where e.dept.name like ‘%Dev%'
- 检索 NULL 或空关系
- 此查询将返回不包含任何职员的部门以及不属于任何部门的职员。可能应用程序想对其中一个部门分配职员。XREL 的用途是将 e.dept 关系(以及反向角色 d.emps)定义到图模式中。
select d.deptno, d.name from Dept d where d.emps is empty select e.empid, e.name from Emp e where e.dept is null xrel e.dept
- 收集输入参数
- 可以将企业 Bean 的集合作为输入自变量传递到 EJB 介体并可以在 FROM 子句中引用该集合。使用集合参数满足从已激活的企业 Bean 的用户集合构造数据图的需求。
select d.deptno, d.name from ((Dept) ?1) as d select e.empid, e.name from in(d.emps) as e where e.salary > 10
通过应用查询谓词并构造数据图,给定的查询对 Dept Bean 及相关 Emp Bean 的集合执行迭代。将从 Bean 的当前值获取值。使用 EJB 集合参数的程序的示例。// this method runs in an EJB context and within a transaction scope public DataGraph myServiceMethod() { InitialContext ic = new InitialContext(); DeptLocalHome deptHome = ic.lookup("java:comp/env/ejb/Dept"); Integer deptKey = new Integer(10); DeptEJB dept = deptHome.findByPrimaryKey( deptKey)); Iterator i = dept.getEmps().iterator(); while (i.hasNext()) { EmpEJB e = (EmpEJB)i.next(); e.setSalary( e.getSalary() * 1.10); // give everyone a 10% raise } // create the query collection parameter Collection c = new LinkedList(); c.add(dept); Object[] parms = new Object[] { c}; // put ejb collection in parm array. // collection containing the dept EJB is passed to EJB Mediator String[] query = new String[] { "select d.deptno, d.name from ((Dept)?1 ) as d", "select e.empid, e.name, e.salary " + " from in (d.employees) as e", "select p.projno, p.name from in (d.projects) as p" }; Mediator m = EJBMediatorFactory.getInstance().createMediator(query, parms); DataGraph dg = m.getGraph(); return dg; // the DataGraph contains the updated and as yet uncommitted // salary information. Dept and Emp data is fetched through // EJB instances active in the EJBContainer. // Project data is retrieved from database using // container managed relationships. }
- 使用 MediatorAdapter
在此示例中,适配器处理 EMP 数据对象的 CREATE 事件。从数据对象中抽取名称和薪水值,并将其传递到 EmpLocalHome 上的创建方法。
create 方法返回 Emp EJB 的实例并且将主键值复制回 DataObject。然后,调用者可以获得生成的键值。处理后,适配器返回值 true。适配器忽略所有其他更改,并且由 EJB 介体来处理这些更改。
package com.example; import com.ibm.websphere.sdo.mediator.ejb.*; import javax.naming.InitialContext; import commonj.sdo.ChangeSummary; import commonj.sdo.DataObject; import commonj.sdo.DataGraph; import commonj.sdo.ChangeSummary; // example of Adapter class calling a EJB create method. public class SalaryAdapter implements MediatorAdapter{ ChangeSummary log = null; EmpLocalHome empHome = null; public boolean applyChange(DataObject object, int phase){ if (object.getType().getName().equals("Emp") && phase == MediatorAdapter.CREATE){ try{ String name = object.getString("name"); double salary = object.getDouble("salary"); EmpLocal emp = empHome.create(name, salary); object.set("empid", emp.getPrimaryKey() ); // set primary key in SDO return true; } catch(Exception e){ // error handling code goes here } } return true; } public void init (ChangeSummary log){ try { this.log = log; InitialContext ic = new InitialContext(); empHome = (EmpLocalHome)ic.lookup( "java:comp/env/ejb/Emp"); } catch (Exception e) { // error handling code goes here } } public void end(){} }