使用manyToOne关系休眠自定义类型



我想要什么:类别地址,代表全球范围内的地址,我也有国家实体,我想在这里使用它作为关系,以降低在某个国家拥有地址的风险,我会指定(值得缓解吗?(

我的一般问题是,这可能吗?

顺便说一句,我在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();
}
}

我设法告诉hibernate,通过弃用的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代码?

谢谢!

在JPA/Hibernate中,如果您可以控制代码,那么这些类型最好表示为可嵌入类型。复合/自定义类型API更适合于无法更改该类型的源代码的情况。

我建议您创建一个可嵌入的存储ISO代码的程序,如下所示:

@Embeddable
public class Country {
private String iso;
}

请记住,如果重用此类型,则可能需要通过使用站点上的@AttributeOverride更改列名。

最新更新