Как сопоставить 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. Я просто предоставляю версию его ответа без @TypeDef
s и т. д. для двух сценариев:
- Валюта хранится как
CHAR(3)
в MySQL для лучшей читаемости данных людьми с использованием 3-хбуквенного кода ISO-4217 - Валюта хранится как
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);