在休眠状态下不会从Criteria Builder查询中调用UserType api方法 [英] UserType api methods are not called from Criteria Builder query in hibernate

查看:141
本文介绍了在休眠状态下不会从Criteria Builder查询中调用UserType api方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一种情况,我使用 org.hibernate.usertype.UserType 将自定义用户类型用于冬眠中的实体字段.

I have a scenario where i use a custom user type for a entity field in hibernate using the org.hibernate.usertype.UserType.

这是将日期转换为UTC

It's a date conversion to UTC

    import org.hibernate.usertype.ParameterizedType;
    import org.hibernate.usertype.UserType;

    public final class UTCTimestampType implements ParameterizedType, UserType
    {..}

我的实体类如下所示

@Entity
public class Person extends AbstractPerson
{
    @Column(name = "BIRTH_DT_TM")
    @Type(type = "com.myexample.hibernate.types.UTCTimestampType")
    protected Date birthDtTm;
}

当当前时间大于出生日期时,我有两个查询要从Db撤退人员

I have two queries to retreive person from Db when current time is greater than brith date

1)jpql中的一个,它实际上按预期方式调用了UserType#nullSafeSet

1)One in jpql, which actually calls the UserType#nullSafeSet as expected

2),但是如果我通过条件构建器构建相同的查询,则永远不会调用类UTCTimestampType中的 UserType#nullSafeSet 实现,而只是执行查询.

2) but if i build the same query via criteria builder the UserType#nullSafeSet implementation in the class UTCTimestampType is never get called and the query just executes.

我不确定为什么会发生这种情况

Am not sure why this happens

这是案例(1)的示例单元测试

this i my sample unit test for case (1)

        String query = "SELECT pFROM Person p where p.birthDtTm = :now";
        Query q = entityManager.createQuery(query);
        q.setParameter("now", new Date());

        List<Person> persons= q.getResultList();

但是我的条件查询没有通过我的自定义UserType类

But my criteria query doesn't go through my custom UserType class

        CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
        CriteriaQuery<Person> criteriaQuery = criteriaBuilder.createQuery(Person.class);
        Root<Person> root = criteriaQuery.from(Person.class);

        Predicate predicate = criteriaBuilder.greaterThanOrEqualTo(
                root.get(Person_.birthDtTm), new Date());

        criteriaQuery.where(predicate);
        criteriaQuery.select(root);

        TypedQuery<Person> q = entityManager.createQuery(criteriaQuery2);
        List<Person> persons = q.getResultList();

我希望在执行查询之前将出生日期字段转换为UTC时区,这在jpql查询中有效,但是在条件构建器中,永远不会调用自定义类型,并且查询会随着时间的推移而执行. 我的最终sql语句应该是 例如:SELECT * FROM Person p,其中p.birthDtTm =日期;

I want the birth date field to be converted to UTC time zone before my query is executed, this worked in jpql query, but in criteria builder the custom type is never called and the query executes with the passed in time. My end sql statment should be Ex:SELECT * FROM Person p where p.birthDtTm = date;

日期位于UTC时区

推荐答案

此处的问题是在休眠版本中,直到"hibernate-core"版本= 5.1.5.Final" "hibernate-entitymanager"版本= 5.1.5.Final" ,任何使用实施的用户特定类型 不支持 org.hibernate.usertype.UserType ,因为休眠只确认 org.hibernate.type.CompositeCustomType ,即使用 org.hibernate.usertype实现的用户类型. CompositeUserType , 可以在类

The problem here was that in hibernate version till "hibernate-core" "version = 5.1.5.Final" and "hibernate-entitymanager" "version = 5.1.5.Final" , any user specific types implemented using org.hibernate.usertype.UserType is not supported, since hibernate only acknowledges org.hibernate.type.CompositeCustomType i.e. user types implemented using org.hibernate.usertype.CompositeUserType, this can be seen in the class

org.hibernate.jpa.internal.QueryImpl#mightNeedRedefinition

org.hibernate.jpa.internal.QueryImpl#mightNeedRedefinition

private boolean mightNeedRedefinition(Class javaType, Type expectedType)
{
    // only redefine dates/times/timestamps that are not wrapped in a CompositeCustomType
    if(expectedType == null)
    {
        return java.util.Date.class.isAssignableFrom(javaType);
    }
    else
    {
        return java.util.Date.class.isAssignableFrom(javaType)
                && !CompositeCustomType.class.isAssignableFrom(expectedType.getClass());
    }
}

我认为这是hibernate版本中的错误,这些问题已从"hibernate-core"版本= 5.2.0.Final"及更高版本进行了修复[注意:这些需要jdk8]

I believe this to be a bug in the hibernate versions, these have been fixed from "hibernate-core" "version = 5.2.0.Final" and higher version [note: these require jdk8]

所以有两种方法可以达到结果,

So there are two ways to achieve the result,

1)更新"hibernate-core"版本= 5.2.0.Final"或更高版本[注意:从此版本开始,hibernate-entitymanager Hibernate的JPA支持已合并到hibernate-core模块中]

1) update "hibernate-core" "version = 5.2.0.Final" or above [Note: from this version onwards hibernate-entitymanager Hibernate's JPA support has been merged into the hibernate-core module]

如果目前无法转到休眠核心"版本= 5.2.0.Final",则下面的两个可能会派上用场,

if a move to "hibernate-core" "version = 5.2.0.Final" is not possible at the moment, then the below two might come in handy,

2)具有自定义用户类型的Java日期类型的任何字段都应实现CompositeUserType

2) any fields of java date types with custom user type should implement the CompositeUserType

(或)

3)如果用户类型实现了org.hibernate.usertype.UserType,这是一种周密的解决方法[注:强烈建议不要这样做]

3) a hacky way of getting around if the user type implements org.hibernate.usertype.UserType [note: this is highly discouraged]

这是一种解决方法,目的是 为相应的谓词创建ParameterExpression 然后将其发送给谓词,仅在查询创建完成后才分配set参数.

The is a hack to workaround this is to, create a ParameterExpression for the corresponding predicate then send that to the predicate and only assign the set parameter only when the query creation is completed.

        CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
        CriteriaQuery<Person> criteriaQuery = criteriaBuilder.createQuery(Person.class);
        Root<Person> root = criteriaQuery.from(Person.class);

        ParameterExpression<Date> p = criteriaBuilder.parameter(Date.class);
        Predicate predicate = criteriaBuilder.greaterThanOrEqualTo(root.get(Person_.birthDtTm), p);

        criteriaQuery.where(predicate);
        criteriaQuery.select(root);

        TypedQuery<Person> q = entityManager.createQuery(criteriaQuery2);
        query.setParameter(p, new Date();
        List<Person> persons = q.getResultList();

但有风险,因为如果在标准查询的开发过程中遗漏了单个参数,则对于会话的重新审核,只会应用休眠的自定义类型.

but its risky since if a single parameter is missed in the development of the criteria query, then for the reamining of the session only hibernates custom type will be applied.

这篇关于在休眠状态下不会从Criteria Builder查询中调用UserType api方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆