ОШИБКА Таблица с этим именем [user_address], уже связанная с объектом, при использовании той же таблицы соединения для ссылки на подклассы ассоциированного объекта

java hibernate jpa

1184 просмотра

3 ответа

Используя Spring Boot Starter, я пытаюсь создать простой пример проекта, в котором участвует пользователь с несколькими полями адреса. Я экспериментирую с использованием @DiscriminatorColumn и @DiscriminatorValue, чтобы различать разные типы адресов, которые может иметь пользователь.

Вот сокращенный образец таблиц в моем проекте:

CREATE TABLE user ( id INT AUTO_INCREMENT);
CREATE TABLE user_address ( user_id INT, address_id INT);
CREATE TABLE address ( id INT AUTO_INCREMENT, TYPE VARCHAR(31));

И вот классы, к которым я пытаюсь присоединиться:

@Entity
@DiscriminatorColumn(name = "type")
public class Address {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    private String type;
}

@Entity
@DiscriminatorValue("HOME")
public class HomeAddress extends Address {}

@Entity
@DiscriminatorValue("CURRENT")
public class CurrentAddress extends Address{}

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    private String type;

    @OneToOne
    @JoinTable(
        name = "user_address",
        joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "id")},
        inverseJoinColumns = {@JoinColumn(name = "address_id", referencedColumnName = "id")}
    )
    private HomeAddress homeAddress;

    @OneToOne
    @JoinTable(
        name = "user_address",
        joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "id")},
        inverseJoinColumns = {@JoinColumn(name = "address_id", referencedColumnName = "id")}
    )
    private CurrentAddress currentAddress;

}

Я пытался заменить @OneToOneна, @OneToManyно все равно это не работает.

Причина, по которой я хочу это сделать, заключается в том, что я думаю связать Адрес с другими объектами. Например, ShippingAddress для заказа или LocationAddress для здания и т. Д.

Вот дамп ошибки:

Caused by: org.hibernate.boot.spi.InFlightMetadataCollector$DuplicateSecondaryTableException: Table with that name [user_address] already associated with entity
    at org.hibernate.boot.internal.InFlightMetadataCollectorImpl$EntityTableXrefImpl.addSecondaryTable(InFlightMetadataCollectorImpl.java:1420) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final]
    at org.hibernate.cfg.annotations.EntityBinder.addJoin(EntityBinder.java:972) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final]
    at org.hibernate.cfg.annotations.EntityBinder.addJoin(EntityBinder.java:868) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final]
    at org.hibernate.cfg.ClassPropertyHolder.addJoin(ClassPropertyHolder.java:207) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final]
    at org.hibernate.cfg.AnnotationBinder.processElementAnnotations(AnnotationBinder.java:1792) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final]
    at org.hibernate.cfg.AnnotationBinder.processIdPropertiesIfNotAlready(AnnotationBinder.java:904) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final]
    at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:731) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final]
    at org.hibernate.boot.model.source.internal.annotations.AnnotationMetadataSourceProcessorImpl.processEntityHierarchies(AnnotationMetadataSourceProcessorImpl.java:245) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final]
    at org.hibernate.boot.model.process.spi.MetadataBuildingProcess$1.processEntityHierarchies(MetadataBuildingProcess.java:222) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final]
    at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:265) ~[hibernate-core-5.0.9.Final.jar:5.0.9.Final]
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:847) ~[hibernate-entitymanager-5.0.9.Final.jar:5.0.9.Final]
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:874) ~[hibernate-entitymanager-5.0.9.Final.jar:5.0.9.Final]
    at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:60) ~[spring-orm-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:338) ~[spring-orm-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:373) ~[spring-orm-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:362) ~[spring-orm-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1637) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1574) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    ... 16 common frames omitted
Автор: Tony Alejandro Источник Размещён: 08.11.2019 11:05

Ответы (3)


2 плюса

К сожалению, вы не можете создать отдельные отношения для двух типов адресов, так как чистый JPA не способен «различать» результаты объединений в запросах, т.е. не создает объединения, используя значение дискриминатора для получения только объектов определенного типа для ассоциации и другого типа для другой ассоциации. Hibernate, напротив, имеет методы для этого, но вне спецификации JPA.

Таким образом, единственный способ, которым это работает, - это позволить вам иметь @OneToManyсвязь с объектами Address, давая вам взамен полиморфную коллекцию, содержащую по очереди HomeAddressи CurrentAddressобъекты

У меня была похожая проблема. Единственным решением для меня было работать немного по-другому (и в основном таким образом, что я не любил так сильно, но это все).

В основном у вас есть 4 варианта (и несколько вариантов):

1- имея только одно ( @OneToMany) отношение, просканируйте вашу коллекцию на предмет типа HomeAddressи / или CurrentAddressпосле получения и назначьте их в правильные поля.

2- Измените способ наследования. В этом случае вы можете использовать Адрес как @MappedSuperclassи ваши подклассы как объекты, расширяющие класс адресов. Два класса должны быть отображены в две отдельные таблицы. Вам не нужен соединительный стол. Это мой путь, даже если он мне не очень понравился.

3 - выбросить наследство и использовать 2 отдельные таблицы

4- использовать аннотации в спящем (не jpa) формате.

Извините, что не вставляю код, но я не могу сделать это здесь и сейчас

Автор: Massimo Размещён: 07.12.2016 04:53

1 плюс

Ваша ошибка:

Вызывается: org.hibernate.boot.spi.InFlightMetadataCollector $ DuplicateSecondaryTableException: таблица с таким именем [user_address], уже связанная с сущностью

Вы забыли @Inheritanceаннотацию. Я полагаю, что вы используете одну таблицу для всех классов адресов. Поэтому вы должны уточнить, что вы хотите использовать SINGLE_TABLEстратегию для обработки OOP-> SQL-отображений. Это то, что используется по умолчанию, но вы можете уточнить это, так как более читабельным.

Добавьте его в объявление класса вашей сущности суперкласса: @Inheritance(strategy = InheritanceType.SINGLE_TABLE)

таким образом :

@Entity
@DiscriminatorColumn(name = "type")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class Address {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    private String type;
}

Редактировать :

user_addressиспользуется как объединяемый в нескольких отношениях в Userобъекте. Hibernate создает впечатление, что не принимает его.

Если вы используете одно отношение, вы теряете льготы для классификации адресов.
Если вы можете изменить свою схему, вы можете удалить таблицу соединений и добавить адрес fk для указания идентификатора пользователя. Извините, у меня нет других подсказок.

Автор: davidxxx Размещён: 20.08.2016 09:00

1 плюс

Вы пробовали Атрибут

@ManyToMany

Потому что с этим определением вы будете архивировать то, что у вас есть

A и B, в которых A может содержать родительский экземпляр, для которого в B много дочерних элементов, и наоборот.

Автор: Gatusko Размещён: 07.12.2016 09:12
Вопросы из категории :
32x32