我想要拥有的东西: 类别地址,代表全球范围内的地址,我也确实具有“国家/地区”实体,我想在此使用它作为关系,以减轻我指定的“到某个国家/地区的地址”的风险(是否值得缓解?)
我的一般问题,有可能吗?
顺便说一句,我在Java 11上使用了Hibernate 5.4.6
我们有一个简单的类:
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();
}
}
我设法告诉休眠,通过不赞成使用的TypeFactory(ouch)将有很多类型, 这就是我最终得到的:
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 && city != null && street != null && number != null && zipCode != null) {
/*
********
* How to obtain instance of Country at this spot ?
*******
*/
return new Address(country, city, street, number, zipCode);
}
return null;
}
}
那么有可能在我的CompositeType中建立关系,还是应该停止尝试并只使用我的地址类中的任何国家/地区iso代码?
谢谢!
答案 0 :(得分:0)
在JPA / Hibernate中,如果您控制代码,则此类类型最好表示为可嵌入对象。如果您无法更改类型的源代码,则复合/自定义类型的API更合适。
我建议您创建一个可嵌入存储ISO代码的可嵌入对象,如下所示:
@Embeddable
public class Country {
private String iso;
}
请记住,如果您重复使用此类型,则可能必须在使用站点上通过@AttributeOverride
更改列名称。