java - 使用相同的连接表引用关联实体的子类时,具有该名称 [user_address] 的表已与实体关联

标签 java hibernate jpa

使用 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));

这是我想加入的类(class):

@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;

}

我已经尝试用 @OneToMany 替换 @OneToOne 但它仍然不起作用。

我希望能够这样做的原因是我正在考虑将地址与其他实体相关联。例如,订单的 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

最佳答案

不幸的是,您不能为这两种地址类型建立单独的关系,因为纯 JPA 无法“区分”查询中连接的结果,即不使用鉴别​​器值进行连接以仅获取特定类型的对象对于一个协会和另一个协会的另一种类型。相反,Hibernate 有执行此操作的方法,但超出了 JPA 规范。

所以它唯一的工作方式是让你有一个 @OneToMany 与 Address 对象的关系,作为返回给你一个多态集合包含 依次为 HomeAddressCurrentAddress 对象

我有一个类似的问题。对我来说,唯一的解决办法是稍微改变一下工作方式(基本上以一种我不太喜欢的方式,但仅此而已)。

基本上你有 4 个选项(和几个备选方案):

1- 只有一个 (@OneToMany) 关系,在检索和将它们分配到正确的字段。

2- 改变继承的设计方式。在这种情况下,您可以将地址用作 @MappedSuperclass 并将您的子类用作扩展地址类的实体。这两个类应该映射到两个单独的表中。您不需要连接表。 这就是我进行的方式,即使我不太喜欢它。

3- 抛弃继承并使用 2 个单独的表

4- 使用 hibernate (非 jpa)注释。

很抱歉没有粘贴代码,但我现在不能这样做

关于java - 使用相同的连接表引用关联实体的子类时,具有该名称 [user_address] 的表已与实体关联,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39052265/

相关文章:

java - 如何获取列表的大小(其中列表是类之间的 M2M 映射)

java - JPA 序列跳过值

java - Android中的开/关音乐

java - 使用正则表达式分割引号和逗号内的数据

java - 让本地部署的模块轻松加入集成环境的流程

hibernate - 存储过程更新数据库后从数据库重新加载对象,而不是缓存?

java - 使用@EnableGlobalMethodSecurity(prePostEnabled = true) 时出错

java - 应用程序卡在 hibernate 状态 txOracle.commit();

java - 在循环中运行 nativeQuery 不会返回正确的数据

java - 使用@ManyToMany 时如何将其他列添加到结果表中?