【问题标题】:How do I make Hibernate custom types apply to aggregate functions?如何使 Hibernate 自定义类型应用于聚合函数?
【发布时间】:2020-12-14 18:54:57
【问题描述】:

我们正在更新定义自定义货币类型的 Hibernate (3.6) 应用程序,扩展 org.hibernate.type.ImmutableType。让它改为扩展 AbstractSingleColumnStandardBasicType 并创建一个 Java 类型描述符以将 Money 存储为 BigInteger 是相当简单的。

但是,应用程序的各个部分都使用 HQL 查询,这些查询在货币字段上执行聚合函数(通常是 SUM)。旧样式,扩展ImmutableType,自动将结果转换为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());
   }
}

【问题讨论】:

    标签: java hibernate aggregate-functions


    【解决方案1】:

    您可以将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.xmlhibernate.cfg.xml 中声明此方言

    然后你就可以在你的 hql 中使用sum_money 函数了:

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

    【讨论】:

      【解决方案2】:

      看起来我们可以通过在我们的 DTO 上添加额外的设置器并根据 Custom type / converter in conjunction with Hibernate's Transformers.aliasToBean 在查询中放置别名来解决这个问题

      这并不理想,但可以让它工作。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-07-04
        • 2015-12-05
        • 2017-04-16
        • 2022-01-12
        相关资源
        最近更新 更多