Eclipselink/JPA:如何使用“@NamedPLSQLStoredFunctionQuery”调用 returns 对象类型的 pl/sql 函数
Eclipselink/JPA: how to call a pl/sql function that returns an object type using '@NamedPLSQLStoredFunctionQuery'
是否可以从 eclipselink 调用 return 对象类型的 pl/sql 函数?
我们构建了一个测试用例,可以从支持 table 中正确选择对象类型。所以我们的实体似乎被正确定义了。但是当调用 pl/sql 函数时,测试用例失败并显示 NoResultException
.
在 eclipselink-log 中语句看起来没问题,但是 return 参数的绑定是空的。我们缺少什么?
[EL Finest]: connection: 2017-03-30 13:51:32.631--ServerSession(1014328909)--Connection(1807648168)--Thread(Thread[main,5,main])--Connection acquired from connection pool [default].
[EL Fine]: sql: 2017-03-30 13:51:32.632--ServerSession(1014328909)--Connection(1807648168)--Thread(Thread[main,5,main])--
DECLARE
RESULTTARGET t_emp;
BEGIN
RESULTTARGET := GET_EMP();
END;
bind => []
[EL Finest]: connection: 2017-03-30 13:51:32.688--ServerSession(1014328909)--Connection(1807648168)--Thread(Thread[main,5,main])--Connection released to connection pool [default].
当我们调用一个 pl/sql 函数 returning 一个 varchar2 时它运行良好,绑定也正常。可能我们只是在@NamedPLSQLStoredFunctionQuery
?
的参数定义中没有找到正确的databaseType
@Before
public void initEM() {
EntityManagerFactory emf = Persistence.createEntityManagerFactory( "test" );
em = emf.createEntityManager();
}
@Test // SUCCEEDS
public void testFind() {
EmpEntity e = em.find( EmpEntity.class, 2 );
assertNotNull( e );
}
@Test // FAILES: javax.persistence.NoResultException: getSingleResult() did not retrieve any entities
public void testNamedFunctionCall() {
EmpEntity e = em.createNamedQuery( "callEmpFunction", EmpEntity.class ).getSingleResult();
assertNotNull( e );
}
@After
public void closeEM() {
em.close();
}
对象类型、支持 table 和 pl/sql 函数定义为
create or replace type T_DEPT as object
( deptno number
, deptname varchar2(40)
, loc varchar2(40)
);
create or replace type T_ADDRESS as object
( street varchar2(40)
, city varchar2(40)
);
create or replace type T_EMP as object
( address t_address
, empno number
, ename varchar2(40)
, dept t_dept
);
create table EMP_OBJECTS
( obj_id number not null primary key
, emp t_emp not null
);
create or replace function GET_EMP
return t_emp
is
v_emp t_emp;
begin
select emp
into v_emp
from emp_objects
where obj_id = 2;
return v_emp;
end;
/
declare
v_dept t_dept := t_dept( 10, 'sales', 'beach' );
v_addr t_address := t_address( 'here', 'there' );
v_emp t_emp := t_emp( v_addr, 1, 'scott', v_dept );
begin
insert into emp_objects
( obj_id, emp )
values
( 2, v_emp );
commit;
end;
我们的 Java 实体和可嵌入的 类 是
@Entity
@Table(name="EMP_OBJECTS")
@NamedPLSQLStoredFunctionQuery( name = "callEmpFunction"
, functionName = "GET_EMP"
, returnParameter = @PLSQLParameter(name = "result", databaseType="t_emp" )
)
public class EmpEntity {
@Id
private int obj_id;
@Structure
private Emp emp;
... getter and setter ...
}
@Embeddable
@Struct(name = "T_EMP", fields = { "addr", "empno", "name", "dept" } )
public class Emp {
@Structure
private Address addr;
private int empno;
private String name;
@Structure
private Dept dept;
}
@Embeddable
@Struct(name="T_ADDRESS", fields={"street","city"})
public class Address {
private String street;
private String city;
}
@Embeddable
@Struct(name="T_DEPT", fields={"deptno","deptname","loc"})
public class Dept {
private int deptno;
private String deptname;
private String loc;
}
我们正在使用 eclipselink 2.6.4 和 oracle 11.2 数据库。
很抱歉回答我自己的问题。经过反复试验,我们找到了两个解决方案,我们想分享一下。
首先:以编程方式创建函数调用并将结果类型设置为OracleObjectType
。注意类型和过程名称的大写名称。这似乎很重要。
@Test
public void testFunctionCall() {
OracleObjectType result = new OracleObjectType();
result.setJavaType( Emp.class );
result.setTypeName( "T_EMP" );
DataReadQuery databaseQuery = new DataReadQuery();
databaseQuery.setResultType(DataReadQuery.VALUE);
PLSQLStoredFunctionCall call = new PLSQLStoredFunctionCall(result);
call.setProcedureName("GET_EMP");
databaseQuery.setCall(call);
Query query = ((JpaEntityManager)em.getDelegate()).createQuery(databaseQuery);
Emp e = (Emp)query.getSingleResult();
assertNotNull( e );
}
其次: 看来有必要把可嵌入的类注解成@Struct
和@OracleObject
每当您想在过程或函数调用中使用它时。通过以下更改,我们以前失败的测试用例成功了。
@Embeddable
@Struct( name = "T_EMP", fields = { "addr", "empno", "name", "dept" } )
@OracleObject( name = "T_EMP", javaType = Emp.class, fields = {} )
public class Emp {
@Structure
private Address addr;
private int empno;
private String name;
@Structure
private Dept dept;
}
@Embeddable
@Struct( name="T_ADDRESS", fields={"street","city"} )
@OracleObject( name = "T_ADDRESS", javaType = Address.class, fields = {} )
public class Address {
private String street;
private String city;
}
@Embeddable
@Struct( name = "T_DEPT", fields = { "deptno", "deptname", "loc" } )
@OracleObject( name = "T_DEPT", javaType = Dept.class, fields = {} )
public class Dept {
private int deptno;
private String deptname;
private String loc;
}
也许对 eclipselink 有更深入了解的人可以评论同时使用 @Struct
和 @OracleObject
的冗余?
是否可以从 eclipselink 调用 return 对象类型的 pl/sql 函数?
我们构建了一个测试用例,可以从支持 table 中正确选择对象类型。所以我们的实体似乎被正确定义了。但是当调用 pl/sql 函数时,测试用例失败并显示 NoResultException
.
在 eclipselink-log 中语句看起来没问题,但是 return 参数的绑定是空的。我们缺少什么?
[EL Finest]: connection: 2017-03-30 13:51:32.631--ServerSession(1014328909)--Connection(1807648168)--Thread(Thread[main,5,main])--Connection acquired from connection pool [default].
[EL Fine]: sql: 2017-03-30 13:51:32.632--ServerSession(1014328909)--Connection(1807648168)--Thread(Thread[main,5,main])--
DECLARE
RESULTTARGET t_emp;
BEGIN
RESULTTARGET := GET_EMP();
END;
bind => []
[EL Finest]: connection: 2017-03-30 13:51:32.688--ServerSession(1014328909)--Connection(1807648168)--Thread(Thread[main,5,main])--Connection released to connection pool [default].
当我们调用一个 pl/sql 函数 returning 一个 varchar2 时它运行良好,绑定也正常。可能我们只是在@NamedPLSQLStoredFunctionQuery
?
databaseType
@Before
public void initEM() {
EntityManagerFactory emf = Persistence.createEntityManagerFactory( "test" );
em = emf.createEntityManager();
}
@Test // SUCCEEDS
public void testFind() {
EmpEntity e = em.find( EmpEntity.class, 2 );
assertNotNull( e );
}
@Test // FAILES: javax.persistence.NoResultException: getSingleResult() did not retrieve any entities
public void testNamedFunctionCall() {
EmpEntity e = em.createNamedQuery( "callEmpFunction", EmpEntity.class ).getSingleResult();
assertNotNull( e );
}
@After
public void closeEM() {
em.close();
}
对象类型、支持 table 和 pl/sql 函数定义为
create or replace type T_DEPT as object
( deptno number
, deptname varchar2(40)
, loc varchar2(40)
);
create or replace type T_ADDRESS as object
( street varchar2(40)
, city varchar2(40)
);
create or replace type T_EMP as object
( address t_address
, empno number
, ename varchar2(40)
, dept t_dept
);
create table EMP_OBJECTS
( obj_id number not null primary key
, emp t_emp not null
);
create or replace function GET_EMP
return t_emp
is
v_emp t_emp;
begin
select emp
into v_emp
from emp_objects
where obj_id = 2;
return v_emp;
end;
/
declare
v_dept t_dept := t_dept( 10, 'sales', 'beach' );
v_addr t_address := t_address( 'here', 'there' );
v_emp t_emp := t_emp( v_addr, 1, 'scott', v_dept );
begin
insert into emp_objects
( obj_id, emp )
values
( 2, v_emp );
commit;
end;
我们的 Java 实体和可嵌入的 类 是
@Entity
@Table(name="EMP_OBJECTS")
@NamedPLSQLStoredFunctionQuery( name = "callEmpFunction"
, functionName = "GET_EMP"
, returnParameter = @PLSQLParameter(name = "result", databaseType="t_emp" )
)
public class EmpEntity {
@Id
private int obj_id;
@Structure
private Emp emp;
... getter and setter ...
}
@Embeddable
@Struct(name = "T_EMP", fields = { "addr", "empno", "name", "dept" } )
public class Emp {
@Structure
private Address addr;
private int empno;
private String name;
@Structure
private Dept dept;
}
@Embeddable
@Struct(name="T_ADDRESS", fields={"street","city"})
public class Address {
private String street;
private String city;
}
@Embeddable
@Struct(name="T_DEPT", fields={"deptno","deptname","loc"})
public class Dept {
private int deptno;
private String deptname;
private String loc;
}
我们正在使用 eclipselink 2.6.4 和 oracle 11.2 数据库。
很抱歉回答我自己的问题。经过反复试验,我们找到了两个解决方案,我们想分享一下。
首先:以编程方式创建函数调用并将结果类型设置为OracleObjectType
。注意类型和过程名称的大写名称。这似乎很重要。
@Test
public void testFunctionCall() {
OracleObjectType result = new OracleObjectType();
result.setJavaType( Emp.class );
result.setTypeName( "T_EMP" );
DataReadQuery databaseQuery = new DataReadQuery();
databaseQuery.setResultType(DataReadQuery.VALUE);
PLSQLStoredFunctionCall call = new PLSQLStoredFunctionCall(result);
call.setProcedureName("GET_EMP");
databaseQuery.setCall(call);
Query query = ((JpaEntityManager)em.getDelegate()).createQuery(databaseQuery);
Emp e = (Emp)query.getSingleResult();
assertNotNull( e );
}
其次: 看来有必要把可嵌入的类注解成@Struct
和@OracleObject
每当您想在过程或函数调用中使用它时。通过以下更改,我们以前失败的测试用例成功了。
@Embeddable
@Struct( name = "T_EMP", fields = { "addr", "empno", "name", "dept" } )
@OracleObject( name = "T_EMP", javaType = Emp.class, fields = {} )
public class Emp {
@Structure
private Address addr;
private int empno;
private String name;
@Structure
private Dept dept;
}
@Embeddable
@Struct( name="T_ADDRESS", fields={"street","city"} )
@OracleObject( name = "T_ADDRESS", javaType = Address.class, fields = {} )
public class Address {
private String street;
private String city;
}
@Embeddable
@Struct( name = "T_DEPT", fields = { "deptno", "deptname", "loc" } )
@OracleObject( name = "T_DEPT", javaType = Dept.class, fields = {} )
public class Dept {
private int deptno;
private String deptname;
private String loc;
}
也许对 eclipselink 有更深入了解的人可以评论同时使用 @Struct
和 @OracleObject
的冗余?