2016-08-20 83 views
9

使用Spring Boot启动程序,我试图创建一个简单的示例项目,该项目涉及具有多个地址字段。我正在尝试使用@DiscriminatorColumn和@ DiscriminatorValue来区分用户可能拥有的不同类型的地址。当使用相同的连接表来引用关联实体的子类时,具有该名称[user_address]的实体已经与实体关联

这是在我的项目中各表的缩写样本:

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; 

} 

我试着@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 
+0

从概念上讲,送货地址与家庭地址相同,与账单地址相同。为什么你需要不同的具体实现? – christopher

+0

你应该把错误日志放在你的问题中,因为它可能会在有外部主机的时候消失。 – davidxxx

+0

共享关系不是JPA规范的一部分。使用它们将是不可移植的,并且JPA提供程序是特定的。 FWIW –

回答

1

你的错误是:

Caused by: org.hibernate.boot.spi.InFlightMetadataCollector$DuplicateSecondaryTableException: Table with that name [user_address] already associated with entity

你forgoten的@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被用作多种关系jointable User实体。 Hibernate给人的印象是它不接受它。

如果您使用单个关系,您将失去对分类地址的好处。
如果您可能更改模式,则可以删除连接表并在地址中添加fk以指定userId。对不起,我没有其他线索。

+0

不幸的是,它仍然会产生相同的错误信息。 –

+0

对不起。我编辑了我的回答 – davidxxx

+0

我很感谢帮助我的努力。 –

2

不幸的是,你不能为这两种地址类型建立单独的关系,因为纯粹的JPA不能'区别'查询中的连接结果,即不使用鉴别​​器值进行连接,只获得某个确定的对象为另一个关联键入一个关联和另一个类型。相反,Hibernate有办法做到这一点,但脱离了JPA规范。

所以它的工作原理是让你有地址对象@OneToMany关系,给你的回报又含有 HomeAddressCurrentAddress对象

多态集合的唯一途径我哈德一个类似的问题。对我来说,唯一的解决方案是工作方式有点不同(基本上我不喜欢这么多,但就是这样)。

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

1-只有一个(@OneToMany)的关系,扫描收集HomeAddress类型和/或CurrentAddress的对象后取回,并将它们分配到正确的领域。

2-改变继承的设计方式。在这种情况下,您可以使用地址作为@MappedSuperclass和您的子类作为扩展地址类的实体。这两个类应映射在两个分开的表中。你不需要连接表。 这就是我继续的方式,即使我不太喜欢它。

3-扔掉继承并使用2个独立的表

4-使用休眠(非JPA)注释。

对不起,不是粘贴代码,但我无法在这里做&现在

1

你有没有尝试过的属性

@ManyToMany

因为with this definition你会归档你有什么

A and B in which A may contain a parent instance for which there are many children in B and vice versa.

相关问题