【问题标题】:Joda-Money persistence via hibernate通过休眠的 Joda-Money 持久性
【发布时间】:2012-01-07 11:07:58
【问题描述】:

有一个 provides Hibernate persistence 的 JodaTime 库。最近我开始查看 Joda-Money 并开始了解如何使用 hibernate 进行持久化,但我没有看到任何库。

有什么建议吗?

【问题讨论】:

    标签: java hibernate joda-money


    【解决方案1】:

    由于 Sudarshan 回答中的示例链接已损坏,因此这里是 org.joda.money.BigMoney 的简单自定义用户类型的实现,它将货币对象保留在金额和货币两列中)以及如何使用它的示例。 org.joda.money.Money 的效果相同。

    package test;
    
    import java.io.Serializable;
    import java.math.BigDecimal;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.util.Currency;
    
    import org.apache.commons.lang.ObjectUtils;
    import org.hibernate.HibernateException;
    import org.hibernate.engine.spi.SessionImplementor;
    import org.hibernate.type.StandardBasicTypes;
    import org.hibernate.type.Type;
    import org.hibernate.usertype.CompositeUserType;
    import org.joda.money.BigMoney;
    import org.joda.money.CurrencyUnit;
    
    public class MoneyUserType implements CompositeUserType
    {
        private static final String[] PROPERTY_NAMES = {"amount", "currencyUnit"};
        private static final Type[] PROPERTY_TYPES = {StandardBasicTypes.BIG_DECIMAL, StandardBasicTypes.CURRENCY};
    
        public MoneyUserType()
        {
            super();
        }
    
        public Object assemble(final Serializable cached, final SessionImplementor session, final Object owner)
        throws HibernateException
        {
            return cached;
        }
    
        public Serializable disassemble(final Object value, final SessionImplementor session) throws HibernateException
        {
            return (Serializable) value;
        }
    
        public String[] getPropertyNames()
        {
            return PROPERTY_NAMES.clone();
        }
    
        public Type[] getPropertyTypes()
        {
            return PROPERTY_TYPES.clone();
        }
    
        public Object getPropertyValue(final Object component, final int property) throws HibernateException
        {
            BigMoney money = (BigMoney) component;
            return (property == 0) ? money.getAmount() : money.getCurrencyUnit().toCurrency();
        }
    
        public Object nullSafeGet(final ResultSet rs, final String[] names, final SessionImplementor session,
        final Object owner) throws HibernateException, SQLException
        {
            BigDecimal amount = StandardBasicTypes.BIG_DECIMAL.nullSafeGet(rs, names[0], session);
            Currency currency = StandardBasicTypes.CURRENCY.nullSafeGet(rs, names[1], session);
            return BigMoney.of(CurrencyUnit.of(currency), amount);
        }
    
        public void nullSafeSet(final PreparedStatement st, final Object value, final int index,
        final SessionImplementor session) throws HibernateException, SQLException
        {
            BigMoney money = (BigMoney) value;
            BigDecimal amount = (money == null) ? null : money.getAmount();
            Currency currency = (money == null) ? null : money.getCurrencyUnit().toCurrency();
    
            StandardBasicTypes.BIG_DECIMAL.nullSafeSet(st, amount, index, session);
            StandardBasicTypes.CURRENCY.nullSafeSet(st, currency, index + 1, session);
        }
    
        public Object replace(final Object original, final Object target, final SessionImplementor session,
        final Object owner) throws HibernateException
        {
            return deepCopy(original);
        }
    
        public void setPropertyValue(final Object component, final int property, final Object value)
        throws HibernateException
        {
            throw new HibernateException("Money is immutable.");
        }
    
        public Object deepCopy(final Object value) throws HibernateException
        {
            return (value != null) ? BigMoney.of(((BigMoney) value).getCurrencyUnit(),
            ((BigMoney) value).getAmount()) : null;
        }
    
        public boolean equals(final Object x, final Object y) throws HibernateException
        {
            return ObjectUtils.equals(x, y);
        }
    
        public int hashCode(final Object x) throws HibernateException
        {
            return ObjectUtils.hashCode(x);
        }
    
        public boolean isMutable()
        {
            return false;
        }
    
        public Class<?> returnedClass()
        {
            return BigMoney.class;
        }
    }
    

    用法:

    @Type(type = "test.MoneyUserType")
    @Columns(columns = {@Column(name = "AMOUNT"), @Column(name = "CURRENCY")})
    private BigMoney money;
    

    【讨论】:

      【解决方案2】:

      User Type 项目包括 Joda Money 支持。

      【讨论】:

        【解决方案3】:

        User Type 项目从 3.0.0 版本开始提供对 joda-money 0.6 的支持。但是请注意,这需要Hibernate 4。当前的 joda-money 版本也是 0.8

        如果您想将它与 Hibernate 3 一起使用,请使用 Sudarshan anwser 中的示例(在撰写本文时它已被窃听)。

        【讨论】:

        • 我认为这是现在最好的答案。
        【解决方案4】:

        好的,我采纳了您的建议,并为 Joda 库中定义的 Money 制作了一个自定义类型,作为参考,人们可以查看它here,在此处使用并测试自定义类型 here

        【讨论】:

        • 我认为您的实现在setPropertyValue() 中存在错误 - Money 对象是不可变的,money.withAmount((BigDecimal) value); 只是创建了一个新对象
        • 点已经做出改变:),但是我不确定hibernate何时调用setPropertyValue()方法,根据我的分析,只有nullSafeSet方法似乎被hibernate调用。跨度>
        • 嗯...您知道您仍然只是更改局部变量吗?我认为为不可变对象实现此方法的唯一正确方法是抛出 UnsupportedOperationException。幸运的是,正如你所说,它似乎没有被调用。
        • 是的,我同意,你说的,我猜是仓促行事
        【解决方案5】:

        Based on http://jadira.sourceforge.net

        货币类型通常由货币和金额组成。 Jadira 可以使用参数配置的货币仅将金额存储到数据库中。例如:

        @Column
        @Type(type = "org.jadira.usertype.moneyandcurrency.joda.PersistentMoneyAmount",
            parameters = {@org.hibernate.annotations.Parameter(name = "currencyCode", value = "USD")})
        private Money money;
        
        Alternatively, with other types two columns to hold the amount an currency:
        
        @Columns(columns = { @Column(name = "MY_CURRENCY"), @Column(name = "MY_AMOUNT") })
        @Type(type = "org.jadira.usertype.moneyandcurrency.joda.PersistentMoneyAmountAndCurrency")
        private Money money;
        

        【讨论】:

          【解决方案6】:

          Joda-Money 非常新,因此没有人为其提供 Hibernate 映射也就不足为奇了。

          但是,编写自定义 Hibernate 类型适配器非常简单。如果您查看 JodaTime 适配器的源代码,您会发现它们非常简单。请参阅docs 了解如何编写自己的代码。

          【讨论】:

          • 你知道的任何与 hibernate 兼容的钱库吗?在适配器方面
          • 好吧,我听取了您的建议,并为 Joda 库中定义的 Money 制作了一个自定义类型,作为参考,人们可以查看它here,用法here 并测试自定义类型here
          • Sudarshan 的评论应该被提升为一个答案(如果可以的话?)IMO。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2010-10-29
          • 1970-01-01
          • 2016-05-03
          • 1970-01-01
          • 2011-09-11
          • 2011-03-30
          • 2012-10-07
          相关资源
          最近更新 更多