Hibernate использует неправильную таблицу для соединения, когда стратегия наследования является типом наследования.Присоединился

#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);
}