#java #hibernate
#java #гибернация
Вопрос:
Что я хотел бы иметь: адрес класса, который представляет адрес по всему миру, также у меня есть объект Country, который я хотел бы использовать здесь в качестве отношения, чтобы снизить риск наличия адреса в стране, которую я бы указал (стоит ли смягчать?)
Мой общий вопрос, возможно ли это вообще?
Кстати, я использую Hibernate 5.4.6 на Java 11
Давайте создадим простой класс:
public class Address {
private Country country;
private String city;
private String street;
private String number;
private String zipCode;
public Address(
final Country country,
final String city,
final String street,
final String number,
final String zipCode
) {
this.country = country;
this.street = street;
this.number = number;
this.city = city;
this.zipCode = zipCode;
}
protected Address() {
}
public String getFormatted() {
return String.format("%s %s, %s %s, %s", street, number, city, zipCode, country);
}
}
,
Страна также прямолинейна:
@Entity
@Table(name = "countries")
public class Country {
@Column
@Id
@NotNull
private String nameIso;
@Column
@NotNull
private String name;
@Column
@NotNull
private boolean isAllowed = false;
protected Country() {
}
public Country(final String nameIso, final String name) {
this.nameIso = nameIso;
this.name = name;
}
public String getNameIso() {
return nameIso;
}
}
И пример объекта, который использует этот класс:
@Entity
@Table(name = "delivery_address")
public class DeliveryAddress {
@Id
@Column
@NotNull
@Type(type = UUID)
private java.util.UUID id;
@ManyToOne(fetch = LAZY)
private User user;
@Column
@NotNull
private Address address;
protected DeliveryAddress() {
}
public DeliveryAddress(User user, Address address) {
this.id = java.util.UUID.randomUUID();
this.user = user;
this.address = address;
}
public Country getCountry() {
return this.address.getCountry();
}
}
Мне удалось сообщить hibernate, что будет много типов для одного типа через устаревший тип (ой),
вот что у меня получилось:
public class AddressType implements CompositeUserType {
public static final String NAME = "address";
private static final int COUNTRY_POSITION = 1;
private static final int CITY_POSITION = 2;
private static final int STREET_POSITION = 3;
private static final int NUMBER_POSITION = 4;
private static final int ZIP_POSITION = 5;
private static final int COUNTRY_INDEX = COUNTRY_POSITION - 1;
private static final int CITY_INDEX = CITY_POSITION - 1;
private static final int STREET_INDEX = STREET_POSITION - 1;
private static final int NUMBER_INDEX = NUMBER_POSITION - 1;
private static final int ZIP_INDEX = ZIP_POSITION - 1;
@Override
public String[] getPropertyNames() {
return new String[]{"country", "city", "street", "number", "zipCode"};
}
@Override
public Type[] getPropertyTypes() {
return new Type[]{
new TypeConfiguration().getTypeResolver().getTypeFactory().manyToOne(Country.class.getCanonicalName()),
StandardBasicTypes.STRING,
StandardBasicTypes.STRING,
StandardBasicTypes.STRING,
StandardBasicTypes.STRING
};
}
@Override
public Object getPropertyValue(final Object component, final int property) throws HibernateException {
if (component == null) {
return null;
}
String propertyValue;
switch (property) {
case COUNTRY_POSITION:
propertyValue = ((Address) component).getCountry().getNameIso();
break;
case CITY_POSITION:
propertyValue = ((Address) component).getCity();
break;
case STREET_POSITION:
propertyValue = ((Address) component).getStreet();
break;
case NUMBER_POSITION:
propertyValue = ((Address) component).getNumber();
break;
case ZIP_POSITION:
propertyValue = ((Address) component).getZipCode();
break;
default:
propertyValue = null;
}
return propertyValue;
}
@Override
public Class returnedClass() {
return Address.class;
}
@Override
public Object nullSafeGet(final ResultSet rs,
final String[] names,
final SharedSessionContractImplementor session,
final Object owner) throws HibernateException, SQLException {
String country = rs.getString(names[COUNTRY_INDEX]);
String city = rs.getString(names[CITY_INDEX]);
String street = rs.getString(names[STREET_INDEX]);
String number = rs.getString(names[NUMBER_INDEX]);
String zipCode = rs.getString(names[ZIP_INDEX]);
if (country != null amp;amp; city != null amp;amp; street != null amp;amp; number != null amp;amp; zipCode != null) {
/*
********
* How to obtain instance of Country at this spot ?
*******
*/
return new Address(country, city, street, number, zipCode);
}
return null;
}
}
Так возможно ли иметь отношение в моем CompositeType или я должен прекратить попытки и использовать только любой код iso страны в моем классе адресов?
Спасибо!
Ответ №1:
В JPA / Hibernate такие типы лучше всего представлять в виде встраиваемых файлов, если вы контролируете код. API составного / пользовательского типа лучше подходит на случай, если вы не можете изменить исходный код типа.
Я бы рекомендовал вам создать встраиваемый файл, который хранит код ISO следующим образом:
@Embeddable
public class Country {
private String iso;
}
Просто имейте в виду, что при повторном использовании этого типа вам, вероятно, придется изменять имена столбцов @AttributeOverride
на сайте использования.