#java #hibernate #jpa #orm
Вопрос:
У меня есть базовая сущность JPA, определенная так (я использую Hibernate 5.4.25.окончательная реализация):
@Entity
@Table(name = "Attributes")
@Inheritance(strategy = InheritanceType.JOINED)
public class BaseAttributeEntity {
@Id
private UUID id;
@Column
private String name;
@ManyToOne
@JoinColumn(name = "containerId")
private ContainerEntity containerEntity;
}
И 2 наследующие сущности, обе похожие на приведенные ниже:
@Entity
@Table(name = "SpecialAttributes")
public class SpecialAttributeEntity extends BaseAttributeEntity {
// ... some more properties
}
Структура таблицы аналогична тому, что описано в документации hibernate, со столбцом идентификатора, определенным для всех 3 таблиц.
У меня также есть другая сущность, содержащая коллекции из 2 сущностей, что-то вроде этого:
@Entity
@Table(name = "Container")
public class ContainerEntity {
@Id
private UUID id;
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "containerEntity")
private Set<SpecialAttributeEntity> specialAttributes = new HashSet<>();
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "containerEntity")
private Set<AnotherSpecialAttributeEntity> anotherSpecialAttributes = new HashSet<>();
}
Когда я пытаюсь запустить некоторую логику поиска и извлечь ContainerEntity
s, я получаю следующую ошибку из базового sql:
org.postgresql.util.PSQLException: ERROR: column specialattr0_.containerId does not exist
Hint: Perhaps you meant to reference the column "specialattr0_1_.containerId".
Базовый sql Hibernate использует для извлечения (я оставил только from
инструкцию, потому что в этом и заключается проблема):
from
"Service"."SpecialAttributes" specialattr0_
inner join "Service"."Attributes" specialattr0_1_ on specialattr0_."id" = specialattr0_1_."id"
left outer join "Service"."Containers" containeren1_ on customattr0_1_."containerId" = containeren1_."id"
В основном проблема заключается в том, что обе сущности «атрибуты» объединяются с помощью containerId
столбца, который определен в таблице базы данных базового класса, но Hibernate пытается создать join
, но используя столбец из таблиц базы данных дочерних классов (где он, очевидно, не существует…).
Я пытался, но до сих пор не нашел решения для этого. Как я могу настроить Hibernate на использование нужной таблицы? Предпочтительно использовать стандартную спецификацию?
Спасибо!
Комментарии:
1. В вашем классе
ContainerEntity
есть два поля с одинаковым именемcustomAttributes
, что невозможно.2. @SternK, отредактировано 10 раз
Ответ №1:
Я думаю, что вы просто не можете использовать @OneToMany(mappedBy)
в данном конкретном случае из-за ограничений в старых версиях Hibernate в сочетании с использованием подтипа. Вам следует переключиться на
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "containerEntity")
private Set<BaseAttributeEntity> attributes = new HashSet<>();
private Set<SpecialAttributeEntity> specialAttributes;
private Set<AnotherSpecialAttributeEntity> anotherSpecialAttributes;
// Put respective instances into separate collections on load
@PostLoad
void postLoad() {
this.specialAttributes = attributes.stream().filter(a instanceof SpecialAttributeEntity).collect(toSet());
this.anotherSpecialAttributes = attributes.stream().filter(a instanceof AnotherSpecialAttributeEntity).collect(toSet());
}
// Controlled write access
public void addAttribute(BaseAttributeEntity a) {
if (a instanceof SpecialAttributeEntity) {
specialAttributes.add(a);
} else {
anotherSpecialAttributes.add(a);
}
attributes.add(a);
}
public void removeAttribute(BaseAttributeEntity a) {
if (a instanceof SpecialAttributeEntity) {
specialAttributes.remove(a);
} else {
anotherSpecialAttributes.remove(a);
}
attributes.remove(a);
}
// Provide read-only access
public Set<SpecialAttributeEntity> getSpecialAttributes() {
return Collections.unmodifiableSet(specialAttributes);
}
public Set<AnotherSpecialAttributeEntity> getAnotherSpecialAttributes() {
return Collections.unmodifiableSet(anotherSpecialAttributes);
}