在hibernate中,不会从Criteria Builder查询中调用UserType api menthods [英] UserType api menthods are not called from Criteria Builder query in hibernate

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

问题描述

我有一个场景,我在使用 org.hibernate.usertype.UserType 的hibernate中为实体字段使用自定义用户类型。



它将日期转换为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)
保护日期birthDtTm;

$ / code>

当前时间大于brith时,我有两个查询来从Db中提取人员日期



1)jpql中的一个,它实际上按预期调用UserType#nullSafeSet
$ b 2)但如果我通过标准构建器构建相同的查询,类中的 UserType#nullSafeSet 实现UTCTimestampType永远不会被调用,查询只会执行。不知道为什么会发生这种情况



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

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

列表< Person> persons = q.getResultList();

但是我的标准查询不会通过我的自定义UserType类

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

谓词谓词= criteriaBuilder.greaterThanOrEqualTo(
root.get(Person_.birthDtTm),new Date());

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

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

我希望在执行查询之前将出生日期字段转换为UTC时区,在jpql查询中,但在条件生成器中,自定义类型从不被调用,并且查询在传入时间内执行。
我的结束sql语句应该是
例如:SELECT * FROM Person p其中p.birthDtTm = date;

其中日期位于UTC时区

谢谢

解决方案

hibernate-coreversion = 5.1.5.Finalhibernate-entitymanagerversion = 5.1.5.Final
org.hibernate.usertype.UserType 不受支持,因为hibernate仅确认 org.hibernate.type.CompositeCustomType ,即使用 org实现的用户类型。 hibernate.usertype.CompositeUserType
这可以在类中看到

org.hibernate.jpa.internal.QueryImpl#mightNeedRedefinition

  private boolean mightNeedRedefinition(javaType类,类型expectedType)
{
//只重定义日期/时间/时间戳不包含在Compo中siteCustomType
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-coreversion = 5.2.0.Final和更高版本[注意:这些需要jdk8]修复过了。因此有两种方法实现结果,
$ b $ 1)更新hibernate-coreversion = 5.2.0.Final或以上[注意:从这个版本开始hibernate-entitymanager Hibernate's JPA支持已经被合并到了hibernate-core模块中。如果转移到hibernate-core版本= 5.2.0.Final是不可能的那么下面两个可能会派上用场,

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


(或)



3)如果用户类型实现org.hibernate.usertype.UserType,非常气馁]



这是一个解决方法,这是
创建一个ParameterEx对相应的谓词
进行压缩,然后将其发送给谓词,并仅在查询创建完成时才分配set参数。

  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);
谓词谓词= 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();

但其风险很大,因为如果在标准查询的开发过程中遗漏了单个参数,那么对于会话的重新定义,只会使用休眠自定义类型。


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

Its a date conversion to UTC

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

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

My entity class is like the below

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

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

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

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

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();

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();

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;

where date is in UTC time zone

Thanks

解决方案

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

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());
    }
}

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) 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]

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) any fields of java date types with custom user type should implement the CompositeUserType

(or)

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

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.

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

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