EclipseLink fails to fetch a scalar Boolean value

2019-07-31 09:11发布

问题:

The following JPA criteria query succeeds on Hibernate (4.2.7 final).

CriteriaBuilder criteriaBuilder=entityManager.getCriteriaBuilder();
CriteriaQuery<Boolean>criteriaQuery=criteriaBuilder.createQuery(Boolean.class);
Root<UserTable> root = criteriaQuery.from(entityManager.getMetamodel().entity(UserTable.class));
criteriaQuery.multiselect(root.get(UserTable_.enabled));

ParameterExpression<String>parameterExpression=criteriaBuilder.parameter(String.class);
criteriaQuery.where(criteriaBuilder.equal(criteriaBuilder.lower(criteriaBuilder.trim(root.get(UserTable_.emailId))), criteriaBuilder.lower(criteriaBuilder.trim(parameterExpression))));
List<Boolean> list = entityManager.createQuery(criteriaQuery).setParameter(parameterExpression, "admin").getResultList();

for(Boolean o:list)
{
    System.out.println("enabled : "+o);
}

It is simply meant to return a scalar Boolean value from MySQL database. The corresponding column is of type TINYINT(1) in MySQL.

It generate the following SQL statement.

SELECT
    usertable0_.enabled as col_0_0_ 
FROM
    social_networking.user_table usertable0_ 
WHERE
    lower(trim(BOTH FROM usertable0_.email_id))=lower(trim(BOTH FROM ?))

The same query fails on EclipseLink (2.5.1) in which case it returns nothing (no error, no exception). It however, generates a correct SQL statement as follows.

SELECT enabled 
FROM projectdb.user_table
WHERE (LOWER(TRIM(email_id)) = LOWER(TRIM(?)))

bind => [admin]

The corresponding JPQL like so,

SELECT u.enabled 
FROM UserTable u 
WHERE lower(trim(u.emailId))=lower(trim(:emailId))

also doesn't get the value in question.


It however, works with additional columns as shown below.

CriteriaBuilder criteriaBuilder=entityManager.getCriteriaBuilder();
CriteriaQuery<Object[]>criteriaQuery=criteriaBuilder.createQuery(Object[].class);
Root<UserTable> root = criteriaQuery.from(entityManager.getMetamodel().entity(UserTable.class));
criteriaQuery.multiselect(root.get(UserTable_.enabled), root.get(UserTable_.firstName));

ParameterExpression<String>parameterExpression=criteriaBuilder.parameter(String.class);
criteriaQuery.where(criteriaBuilder.equal(criteriaBuilder.lower(criteriaBuilder.trim(root.get(UserTable_.emailId))), criteriaBuilder.lower(criteriaBuilder.trim(parameterExpression))));
List<Object[]> list = entityManager.createQuery(criteriaQuery).setParameter(parameterExpression, userName).getResultList();

One extra column root.get(UserTable_.firstName) is added and the return type of CriteriaQuery is changed from CriteriaQuery<Boolean> to CriteriaQuery<Object[]>.

The column is defined as follows in the corresponding entity.

@Basic(optional = false)
@NotNull
@Column(name = "enabled")
private Boolean enabled;  //Getter and setter.

Why doesn't it given a Boolean value in EclipseLink?

回答1:

This is due to EclipseLink bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=340089 which causes EclipseLink to be unable to distinguish the value returned from the SQL query from the construct it uses internally to indicate there were no results. Selecting another value is the only workaround, but it seems simple enough that not many people hit it or just workaround it without commenting or voting for the bug.