首页 > 解决方案 > 如何使 Hibernate 自定义类型应用于聚合函数?

问题描述

我们正在更新一个 Hibernate (3.6) 应用程序,该应用程序定义了一个自定义货币类型,扩展org.hibernate.type.ImmutableType. 让它改为扩展AbstractSingleColumnStandardBasicType并创建一个 Java 类型描述符以存储MoneyBigInteger.

但是,应用程序的各个部分都使用 HQL 查询,这些查询在货币字段上执行聚合函数(通常是 SUM)。旧样式 extendsImmutableType会自动将结果转换为Money,但是使用新样式时,不会发生这种情况;结果是一个 Long。

有谁知道如何让 Hibernate 自定义类型自动转换聚合函数的结果?

老用户类型:

public class MoneyUserType extends ImmutableType {
   private final BigIntegerType bigIntegerType = new BigIntegerType();

   @Override
   public Object fromStringValue(final String string) {
      final BigInteger bigInteger = (BigInteger) bigIntegerType.fromStringValue(string);
      return Money.inCents(bigInteger);
   }

   @Override
   public Object get(final ResultSet rs, final String name) throws SQLException {
      final BigInteger bigInteger = (BigInteger) bigIntegerType.get(rs, name);
      if (null == bigInteger) {
         return null;
      }
      return Money.inCents(bigInteger);
   }

   @Override
   public void set(final PreparedStatement st, final Object object, final int index) throws SQLException {
      final Money money = (Money) object;
      bigIntegerType.set(st, money.getAmountInCents(), index);
   }

   @Override
   public int sqlType() {
      return bigIntegerType.sqlType();
   }

   @Override
   public String toString(final Object object) {
      final Money money = (Money) object;
      return bigIntegerType.toString(money.getAmountInCents());
   }

   public String getName() {
      return Money.class.getName();
   }

   @SuppressWarnings("unchecked")
   public Class getReturnedClass() {
      return Money.class;
   }
}

新用户类型:

public class MoneyUserType extends AbstractSingleColumnStandardBasicType<Money> {
    
   public MoneyUserType() {
       super(BigIntTypeDescriptor.INSTANCE, MoneyJavaTypeDescriptor.INSTANCE);
   }
    
   @Override
   public String getName() {
      return Money.class.getName();
   }
}
    
public class MoneyJavaTypeDescriptor extends AbstractTypeDescriptor<Money> {
    
   public static final MoneyJavaTypeDescriptor INSTANCE = new MoneyJavaTypeDescriptor();
    
   public MoneyJavaTypeDescriptor() {
      super(Money.class, ImmutableMutabilityPlan.INSTANCE);
   }
    
   @Override
   public Money fromString(final String string) {
      final BigInteger bigInteger = BigIntegerTypeDescriptor.INSTANCE.fromString(string);
       return Money.inCents(bigInteger);
   }
    
   @Override
   public <X> X unwrap(Money value, Class<X> type, WrapperOptions options) {
      if (value == null) {
         return null;
      }
      if (type.isAssignableFrom(BigInteger.class)) {
         return (X) value.getAmountInCents();
      }
      if (type.isAssignableFrom(Long.class)) {
         return (X) Long.valueOf(value.getAmountInCents().longValue());
      }
      if (type.isAssignableFrom(Integer.class)) {
         return (X) Integer.valueOf(value.getAmountInCents().intValue());
      }
      throw unknownUnwrap(type);
   }
    
   @Override
   public <X> Money wrap(X value, WrapperOptions options) {
      if (value == null) {
         return null;
      }
      if (Number.class.isInstance(value)) {
         return Money.inCents((Number) value);
      }
      throw unknownWrap(value.getClass());
   }
    
   @Override
   public String toString(final Money money) {
      return BigIntegerTypeDescriptor.INSTANCE.toString(money.getAmountInCents());
   }
}

标签: javahibernateaggregate-functions

解决方案


您可以将INSTANCE静态字段添加到您的MoneyUserType

public class MoneyUserType extends AbstractSingleColumnStandardBasicType<Money> {

   public static final MoneyUserType INSTANCE = new MoneyUserType();

   // ...
}

然后将例如以下函数添加到您的自定义休眠方言中:

public class MyPostgreSQLDialect extends PostgreSQL10Dialect
{
   public MyPostgreSQLDialect()
   {
      registerFunction("sum_money", new StandardSQLFunction("sum", MoneyUserType.INSTANCE));
   }
}

persistence.xml用你的或声明这个方言hibernate.cfg.xml

然后您将能够sum_money在您的 hql 中使用该功能:

Money sum = entityManager.createQuery(
    "select sum_money(m.money) from MoneyEntity m",
     Money.class
).getSingleResult();

推荐阅读