JPA Несколько встроенных полей
Возможно ли, чтобы класс сущности JPA содержал два встроенных поля (@Embedded
)? Примером может служить:
@Entity
public class Person {
@Embedded
public Address home;
@Embedded
public Address work;
}
public class Address {
public String street;
...
}
В этом случае a Person
может содержать два экземпляра Address
- домашний и рабочий. Я использую JPA с внедрением Hibernate. Когда я сгенерирую схему с помощью Hibernate Tools, она включает только один Address
. Я бы хотел, чтобы два встроенных экземпляра Address
, каждый с именами столбцов, которые были отмечены или предварительно занесены в префикс (например, дома и работы). Я знаю @AttributeOverrides
, но это требует, чтобы каждый атрибут был индивидуально переопределен. Это может стать громоздким, если встроенный объект (Address
) становится большим, поскольку каждый столбец должен быть индивидуально переопределен.
Ответы
Ответ 1
Если вы хотите иметь один и тот же тип встраиваемого объекта дважды в одном и том же объекте, значение по умолчанию для столбца не будет работать: по крайней мере один из столбцов должен быть явным. Hibernate выходит за рамки спецификации EJB3 и позволяет вам усилить механизм дефолта через NamingStrategy. DefaultComponentSafeNamingStrategy - небольшое улучшение по сравнению с EJB3NamingStrategy по умолчанию, которое позволяет использовать встроенные объекты по умолчанию, даже если они используются дважды в одном и том же объекте.
Из аннотаций Hibernate Doc: http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#d0e714
Ответ 2
Общий способ JPA для этого - с @AttributeOverride. Это должно работать как в EclipseLink, так и в Hibernate.
@Entity
public class Person {
@AttributeOverrides({
@AttributeOverride(name="street",[email protected](name="homeStreet")),
...
})
@Embedded public Address home;
@AttributeOverrides({
@AttributeOverride(name="street",[email protected](name="workStreet")),
...
})
@Embedded public Address work;
}
@Embeddable public class Address {
@Basic public String street;
...
}
}
Ответ 3
При использовании Eclipse Link альтернатива использованию AttributeOverrides позволяет использовать SessionCustomizer. Это решает проблему для всех объектов за один раз:
public class EmbeddedFieldNamesSessionCustomizer implements SessionCustomizer {
@SuppressWarnings("rawtypes")
@Override
public void customize(Session session) throws Exception {
Map<Class, ClassDescriptor> descriptors = session.getDescriptors();
for (ClassDescriptor classDescriptor : descriptors.values()) {
for (DatabaseMapping databaseMapping : classDescriptor.getMappings()) {
if (databaseMapping.isAggregateObjectMapping()) {
AggregateObjectMapping m = (AggregateObjectMapping) databaseMapping;
Map<String, DatabaseField> mapping = m.getAggregateToSourceFields();
ClassDescriptor refDesc = descriptors.get(m.getReferenceClass());
for (DatabaseMapping refMapping : refDesc.getMappings()) {
if (refMapping.isDirectToFieldMapping()) {
DirectToFieldMapping refDirectMapping = (DirectToFieldMapping) refMapping;
String refFieldName = refDirectMapping.getField().getName();
if (!mapping.containsKey(refFieldName)) {
DatabaseField mappedField = refDirectMapping.getField().clone();
mappedField.setName(m.getAttributeName() + "_" + mappedField.getName());
mapping.put(refFieldName, mappedField);
}
}
}
}
}
}
}
}
Ответ 4
Если вы используете спящий режим, вы также можете использовать другую схему именования, которая добавляет уникальные префиксы к столбцам для одинаковых встроенных полей. См. Автоматическое добавление префикса в имена столбцов для классов @Embeddable