Как сопоставить Joda Money с типом org.jadira.usertype.moneyandcurrency.joda.PersistentMoneyAmountAndCurrency в Hibernate?

Пробую это:

@Type(type = "org.jadira.usertype.moneyandcurrency.joda.PersistentMoneyAmountAndCurrency")
private org.joda.money.Money price;

Получение этого:

org.hibernate.MappingException: property mapping has wrong number of columns:domain.ClientOrderItem.price type: org.jadira.usertype.moneyandcurrency.joda.PersistentMoneyAmountAndCurrency


@Type(type = "org.jadira.usertype.moneyandcurrency.joda.PersistentMoneyAmount",
parameters = {@org.hibernate.annotations.Parameter(name = "currencyCode", value = "USD")})

Работает хорошо, но я хочу хранить валюту в базе данных и иметь возможность использовать разные валюты.

2 ответа

Решение

Вот рабочий пример из Jadira Usertype Unit Tests

    @Entity
    @Table(name = "moneyAmountAndCurrency")
    @TypeDef(name = "testjoda_MoneyAmountWithCurrencyType", typeClass = PersistentMoneyAmountAndCurrency.class)
    public class MoneyAmountAndCurrencyHolder implements Serializable {

    private static final long serialVersionUID = -1674416082110551506L;

    @Columns(columns = { @Column(name = "MY_CURRENCY"), @Column(name = "MY_AMOUNT") })
    @Type(type = "testjoda_MoneyAmountWithCurrencyType")
    private Money money;

Вступление

Это на самом деле не отличается от ответа, данного Chris Pheby. Я просто предоставляю версию его ответа без @TypeDefs и т. д. для двух сценариев:

  1. Валюта хранится как CHAR(3) в MySQL для лучшей читаемости данных людьми с использованием 3-хбуквенного кода ISO-4217
  2. Валюта хранится как SMALLINT в MySQL для незначительного повышения эффективности с использованием 3-значного номера ISO-4217

В обоих случаях компонент суммы Money поле хранится как DECIMAL(9,2) который требует 5 байтов памяти для большинства РСУБД. Конечно, вы можете использовать любой другой точный тип данных, чтобы избежать возможных проблем с точностью, double/float,

Сценарий 1 (3-х буквенное представление валюты)

Мой вымышленный Payment@Entity выглядит так для сценария (1):

package com.fictional;

import org.hibernate.annotations.Columns;
import org.hibernate.annotations.Type;
import org.joda.money.CurrencyUnit;
import org.joda.money.Money;

import javax.persistence.Column;
import javax.persistence.Entity;

/**
 * A fictional payment.
 */
@Entity
public class Payment {

    /**
     * Paid money.
     */
    @Columns(columns = {@Column(name = "paidMoneyCurrency"), @Column(name = "paidMoneyAmount")})
    @Type(type = "org.jadira.usertype.moneyandcurrency.joda.PersistentMoneyAmountAndCurrency")
    private Money paidMoney;


    /**
     * Sample construction of a money object belonging to a payment.
     */
    static public void testPayment()
    {
        Payment p = new Payment();

        p.paidMoney = Money.of(CurrencyUnit.EUR, 1234.56);

        // Hibernate persistence code to insert the new record
    }
}

Статический метод - это всего лишь пример создания такого объекта перед его отправкой в ​​постоянное хранилище.

Соответствующий DDL для базы данных будет следующим:

CREATE TABLE Payment (
    paidMoneyCurrency CHAR(3) NOT NULL,
    paidMoneyAmount DECIMAL(9,2) NOT NULL
);

INSERT Сгенерированный Hibernate оператор выглядит так:

INSERT INTO Payment (paidMoneyCurrency, paidMoneyAmount) VALUES ('EUR', 1234.56);

Сценарий 2 (3-х значное представление валюты)

Для сценария (2) вам нужно будет только изменить @Type аннотация вашего paidMoney поле для чтения PersistentMoneyAmountAndCurrencyAsInteger вместо PersistentMoneyAmountAndCurrency (разница заключается в суффиксе AsInteger в имени класса).

    // :
    // :
    @Type(type = "org.jadira.usertype.moneyandcurrency.joda.PersistentMoneyAmountAndCurrencyAsInteger")
    private Money paidMoney;
    // :
    // :

Весь оставшийся код (даже создание экземпляра Money объект в статическом методе) остается прежним.

Тогда вы получите следующий DDL и соответствующий INSERT оператор, сгенерированный Hibernate (978 это числовой код для EUR автоматически рассчитывается для вас йода деньгами)

CREATE TABLE Payment (
    paidMoneyCurrency SMALLINT NOT NULL,
    paidMoneyAmount DECIMAL(9,2) NOT NULL
);

INSERT INTO Payment (paidMoneyCurrency, paidMoneyAmount) VALUES (978, 1234.56);
Другие вопросы по тегам