EclipseLink JPA CriteriaBuilder生成了无效的SQL语法

时间:2012-05-01 13:57:50

标签: jpa-2.0 eclipselink criteria-api

我有两个对象,都定义为实体,一个包含另一个,如下所示:

@Entity
public class TestC 
{
    @Id @GeneratedValue
    private Integer id;
    @ManyToOne (cascade = {CascadeType.PERSIST, CascadeType.MERGE} )
    TestD d;
} 

@Entity
public class TestD 
{
    @Id @GeneratedValue
    private Integer id;
    String moo;
}    

实体是持久的:

TestC c2 = new TestC();
TestD d2 = new TestD();
d2.moo = "d2";
c2.d = d2;
em.getTransaction().begin();
em.persist(d2);
em.persist(c2);
em.getTransaction().commit();

我正在尝试使用TestD实例查询TestC对象:

CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<TestC> query = builder.createQuery(TestC.class);
Root<TestC> from = query.from(TestC.class);

ParameterExpression<TestD> pe = builder.parameter(TestD.class);

query.where(builder.equal(pe, from.<TestD>get("d")));

TestC found = em.createQuery(query)
    .setParameter(pe, d2)
    .getSingleResult();

但EclipseLink在运行查询时会发出以下错误(注意“(?=)”附近的SQL无效,TestD对象没有列名):

Exception in thread "main" Local Exception Stack: 
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLException: Invalid argument value: java.io.NotSerializableException
Error Code: 0
Call: SELECT t1.ID, t1.D_ID FROM TESTD t0, TESTC t1 WHERE ((? = ) AND (t0.ID = t1.D_ID))
bind => [1 parameter bound]
Query: ReadAllQuery(referenceClass=TestC sql="SELECT t1.ID, t1.D_ID FROM TESTD t0, TESTC t1 WHERE ((? = ) AND (t0.ID = t1.D_ID))")

我是否构建了错误的查询?

感谢您的帮助!

1 个答案:

答案 0 :(得分:1)

JavaDoc中没有记录,但ParameterExpression应该是第二个参数。顺序遵循与相同(表达式x,java.lang.Object y)相同的逻辑。此外,您需要 .select 。 EclipseLink(至少2.3.0)也没有,但根据规范,select / multiselect不可移植:

  

便携式应用程序应使用select或multiselect方法   指定查询的选择列表。不使用的应用程序   这些方法不可移植。

在这些变化之后,正确的方法是:

CriteriaQuery<TestC> query = builder.createQuery(TestC.class);
Root<TestC> from = query.from(TestC.class);

ParameterExpression<TestD> pe = builder.parameter(TestD.class);
query.select(from)
     .where(builder.equal(from.<TestD>get("d"), pe));

TestC found = em.createQuery(query)
                .setParameter(pe, d)
                .getSingleResult();