【问题标题】:Hibernate referencing a primary key that does not existHibernate 引用了一个不存在的主键
【发布时间】:2017-01-09 14:10:18
【问题描述】:

我在尝试部署使用休眠的应用程序时遇到以下错误:

外键 (FK2e496501ee5lgk3viylwiicsa:MANAGED_APP_TO_CON_TO_SRUCT [MANAGED_APP_TO_CONTACT_ID]) 的列数必须与引用的主键 (MANAGED_APPLICATION_TO_CONTACT [CONTACT_ID,MANAGED_APPLICATION_ID]) 的列数相同

但我不确定 hibernate 在这里引用的是什么键。从下面由 Oracle SQL Developer 生成的模型可以看出,CONTACT_ID, MANAGED_APPLICATION_ID 上没有复合主键。 MANAGED_APPLICATION_TO_CONTACT 的主键在序列列MANAGED_APP_TO_CONTACT_ID 上,也就是外键引用的列。

因此,我被引导相信问题出在我的实体中的 JPA 映射中。以下是相关实体(请注意,我选择发布完整实体而不是最小示例,以防问题出在我的实体中没有预料到的地方):

ManagedApplicationToContact:

@Entity
@Table(name = "MANAGED_APPLICATION_TO_CONTACT", schema = "UAM")
public class ManagedApplicationToContact implements java.io.Serializable {


    private Long managedAppToContactId;
    private ManagedApplication managedApplication;
    private Contact contact;
    private Long lastUpdatedBy;
    private Date lastUpdated;

    public ManagedApplicationToContact() {
    }

    public ManagedApplicationToContact(final ManagedApplication managedApplication, final Contact contact, final Long lastUpdatedBy, final Date lastUpdated) {
        this.managedApplication = managedApplication;
        this.contact = contact;
        this.lastUpdatedBy = lastUpdatedBy;
        this.lastUpdated = lastUpdated;
    }

    @SequenceGenerator(name = "generator", sequenceName = "UAM.SEQ_MANAGED_APP_TO_CONTACT", initialValue = 0, allocationSize = 1)
    @Id
    @GeneratedValue(strategy = SEQUENCE, generator = "generator")
    @Column(name = "MANAGED_APP_TO_CONTACT_ID", unique = true, nullable = false, precision = 15, scale = 0)
    public Long getManagedAppToContactId() {
        return this.managedAppToContactId;
    }

    public void setManagedAppToContactId(final Long managedAppToContactId) {
        this.managedAppToContactId = managedAppToContactId;
    }

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "MANAGED_APPLICATION_ID", nullable = false)
    public ManagedApplication getManagedApplication() {
        return this.managedApplication;
    }

    public void setManagedApplication(final ManagedApplication managedApplication) {
        this.managedApplication = managedApplication;
    }

    @Column(name = "LAST_UPDATED_BY", nullable = false, precision = 15, scale = 0)
    public Long getLastUpdatedBy() {
        return this.lastUpdatedBy;
    }

    public void setLastUpdatedBy(final Long lastUpdatedBy) {
        this.lastUpdatedBy = lastUpdatedBy;
    }

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "LAST_UPDATED", length = 7)
    public Date getLastUpdated() {
        return this.lastUpdated;
    }

    public void setLastUpdated(final Date lastUpdated) {
        this.lastUpdated = lastUpdated;
    }

    @ManyToOne
    @JoinColumn(name= "CONTACT_ID", referencedColumnName = "CONTACT_ID", nullable = false)
    public Contact getContact() {
        return contact;
    }

    public void setContact(final Contact contact) {
        this.contact = contact;
    }
}

ManagedAppToConToStruct:

@Entity
@Table(name = "MANAGED_APP_TO_CON_TO_STRUCT", schema = "UAM")
public class ManagedAppToConToStruct {
    @SequenceGenerator(name = "generator", sequenceName = "UAM.MAN_APP_TO_CON_TO_STRUCT_SEQ", allocationSize = 1)

    @Id
    @GeneratedValue(strategy = SEQUENCE, generator = "generator")
    @Column(name = "ID", unique = true, nullable = false)
    private Long id;

    @ManyToOne
    @JoinColumn(name= "MANAGED_APP_TO_CONTACT_ID", referencedColumnName = "MANAGED_APP_TO_CONTACT_ID", nullable = false)
    private ManagedApplicationToContact managedApplicationToContact;

    @ManyToOne
    @JoinColumn(name="STRUCTURE_ID", nullable = false)
    private Structure structure;

    @Column(name = "LAST_UPDATED")
    private LocalDateTime lastUpdated;

    @Column(name = "LAST_UPDATED_BY")
    @Basic
    private Long lastUpdatedBy;

    public Long getId() {
        return id;
    }

    public void setId(final Long id) {
        this.id = id;
    }

    public ManagedApplicationToContact getManagedApplicationToContact() {
        return managedApplicationToContact;
    }

    public void setManagedApplicationToContact(final ManagedApplicationToContact managedApplicationToContact) {
        this.managedApplicationToContact = managedApplicationToContact;
    }

    public Structure getStructure() {
        return structure;
    }

    public void setStructure(final Structure structure) {
        this.structure = structure;
    }

    public LocalDateTime getLastUpdated() {
        return lastUpdated;
    }

    public void setLastUpdated(final LocalDateTime lastUpdated) {
        this.lastUpdated = lastUpdated;
    }

    public Long getLastUpdatedBy() {
        return lastUpdatedBy;
    }

    public void setLastUpdatedBy(final Long lastUpdatedBy) {
        this.lastUpdatedBy = lastUpdatedBy;
    }
} 

我什至使用 IntelliJ IDE 的内置实体生成功能从数据库模式构建这些实体,它生成了相同的映射。我在我的项目中添加了一个 Hibernate JPA facet,而 IntelliJ 表明所有映射都正确完成 - 所以我在这里非常难过。


编辑:为表添加创建语句。

MANAGED_APPLICATION_TO_CONTACT:(这个是从 Oracle SQL Developer 生成的,因为我没有运行的原始脚本)

CREATE TABLE "UAM"."MANAGED_APPLICATION_TO_CONTACT" 
   (    "MANAGED_APP_TO_CONTACT_ID" NUMBER(15,0) NOT NULL ENABLE, 
    "CONTACT_ID" NUMBER(15,0) NOT NULL ENABLE, 
    "MANAGED_APPLICATION_ID" NUMBER(6,0) NOT NULL ENABLE, 
    "LAST_UPDATED_BY" NUMBER, 
    "LAST_UPDATED" DATE, 
     CONSTRAINT "MANAGE_APPLICATION_CONTACT_PK" PRIMARY KEY ("MANAGED_APP_TO_CONTACT_ID")
  USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS 
  STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
  PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
  BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
  TABLESPACE "UAM"  ENABLE, 
     CONSTRAINT "MANAGED_APPLICATION_TO_CO_FK1" FOREIGN KEY ("MANAGED_APPLICATION_ID")
      REFERENCES "UAM"."MANAGED_APPLICATION" ("MANAGED_APPLICATION_ID") ENABLE
   ) SEGMENT CREATION IMMEDIATE 
  PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 
 NOCOMPRESS LOGGING
  STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
  PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1
  BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT)
  TABLESPACE "UAM" ;

MANAGED_APP_TO_CON_TO_STRUCT:(这是用于创建表的实际脚本)

CREATE TABLE UAM.MANAGED_APP_TO_CON_TO_STRUCT (
  ID NUMBER NOT NULL,
  MANAGED_APP_TO_CONTACT_ID NUMBER(15) NOT NULL,
  STRUCTURE_ID NUMBER NOT NULL,
  LAST_UPDATED TIMESTAMP(6) DEFAULT SYSTIMESTAMP NOT NULL,
  LAST_UPDATED_BY NUMBER NOT NULL,
  CONSTRAINT MAN_APP_TO_CON_TO_STRUCT_PK PRIMARY KEY (ID),
  CONSTRAINT MAN_APP_TO_CON_TO_STRUCT_FK01 FOREIGN KEY (MANAGED_APP_TO_CONTACT_ID) REFERENCES UAM.MANAGED_APPLICATION_TO_CONTACT (MANAGED_APP_TO_CONTACT_ID),
  CONSTRAINT MAN_APP_TO_CON_TO_STRUCT_FK02 FOREIGN KEY (STRUCTURE_ID) REFERENCES HIERARCHY.STRUCTURE (STRUCTURE_ID),
  CONSTRAINT MAN_APP_TO_CON_TO_STRUCT_FK03 FOREIGN KEY (LAST_UPDATED_BY) REFERENCES MCT.CONTACT (CONTACT_ID)
);
CREATE UNIQUE INDEX UAM.MAN_APP_TO_CON_TO_STRUCT_IDX01 ON UAM.MANAGED_APP_TO_CON_TO_STRUCT (MANAGED_APP_TO_CONTACT_ID, STRUCTURE_ID);

编辑:添加完整的堆栈跟踪。

2017-01-06 15:34:42.834 ERROR [RMI TCP Connection(5)-127.0.0.1] o.s.web.context.ContextLoader:353 - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'MCT' defined in com.myproject.JpaConfig: Invocation of init method failed; nested exception is org.hibernate.MappingException: Foreign key (FK2e496501ee5lgk3viylwiicsa:MANAGED_APP_TO_CON_TO_STRUCT [MANAGED_APP_TO_CONTACT_ID])) must have same number of columns as the referenced primary key (MANAGED_APPLICATION_TO_CONTACT [CONTACT_ID,MANAGED_APPLICATION_ID])
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1578)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:545)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1054)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:829)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538)
    at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:446)
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:328)
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:107)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4990)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5490)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901)
    at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877)
    at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:649)
    at org.apache.catalina.startup.HostConfig.manageApp(HostConfig.java:1763)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:301)
    at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)
    at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)
    at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:618)
    at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:565)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:301)
    at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)
    at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)
    at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1466)
    at javax.management.remote.rmi.RMIConnectionImpl.access$300(RMIConnectionImpl.java:76)
    at javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1307)
    at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1399)
    at javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:828)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:323)
    at sun.rmi.transport.Transport$1.run(Transport.java:200)
    at sun.rmi.transport.Transport$1.run(Transport.java:197)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:196)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:568)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:826)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$240(TCPTransport.java:683)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$$Lambda$1/1638143133.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:682)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
Caused by: org.hibernate.MappingException: Foreign key (FK2e496501ee5lgk3viylwiicsa:MANAGED_APP_TO_CON_TO_STRUCT [MANAGED_APP_TO_CONTACT_ID])) must have same number of columns as the referenced primary key (MANAGED_APPLICATION_TO_CONTACT [CONTACT_ID,MANAGED_APPLICATION_ID])
    at org.hibernate.mapping.ForeignKey.alignColumns(ForeignKey.java:137)
    at org.hibernate.mapping.ForeignKey.alignColumns(ForeignKey.java:119)
    at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.secondPassCompileForeignKeys(InFlightMetadataCollectorImpl.java:1888)
    at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.secondPassCompileForeignKeys(InFlightMetadataCollectorImpl.java:1808)
    at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1627)
    at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:278)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:847)
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:874)
    at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:60)
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:343)
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:318)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1637)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1574)
    ... 58 common frames omitted

编辑:

还想指出 ManagedApplicationToContact 实体在添加 ManagedAppToConToStruct 之前工作得非常好。

【问题讨论】:

  • 能否请您提供带有堆栈跟踪的完整异常而不是仅提供异常消息?看看链中的哪个组件准确地吐出这个错误可能会很有趣。另外:生成 SQL 创建语句而不是可视化图表可能会更好。您希望对所涉及的内容进行最少解释的视图。
  • @Gimby 添加了堆栈跟踪和创建语句
  • 通常您不应该在SequenceGenerator 中重复使用该名称,但这只是您以后会遇到的另一个问题。这不是你当前的问题。我仍在寻找缺少的东西。其他问题包括JoinColumn中的referencedColumnName应该是另一边的字段名称,而不是列的sql名称。
  • @coladict 有趣,我一直使用相同的名称为 SequenceGenerators 并且从未遇到过任何问题
  • 由于 Hibernate 中注释类的处理顺序,这不是问题,只要您在类中声明它们,但是如果您尝试迁移到 EclipseLink,它将崩溃和烧毁。我想我找到了一些可以帮助你的东西。该 UNIQUE 约束被视为主键,即使它不是正式的主键。 stackoverflow.com/questions/24696358/…

标签: java hibernate jpa hibernate-mapping oracle12c


【解决方案1】:

所以事实证明,我在Contact 实体中有这个映射,它使用MANAGED_APPLICATION_TO_CONTACT 作为连接表来检索与Contact 绑定的ManagedApplication 记录,这导致休眠假设主键入CONTACT_ID,MANAGED_APPLICATION_ID

@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "MANAGED_APPLICATION_TO_CONTACT", schema = "UAM",
        joinColumns = {@JoinColumn(name = "CONTACT_ID",
                referencedColumnName = "CONTACT_ID",
                nullable = false)},
        inverseJoinColumns = {@JoinColumn(name = "MANAGED_APPLICATION_ID",
                referencedColumnName = "MANAGED_APPLICATION_ID",
                nullable = false)})
@OrderBy("name asc")
public Set<ManagedApplication> getManagedApplications() {
    return this.managedApplications;
}

public void setManagedApplications(final Set<ManagedApplication> managedApplications) {
    this.managedApplications = managedApplications;
}

为了纠正这个问题,我去掉了这个映射并将它变成了一个临时方法,它只是将ManagedApplication 记录从已经正确映射的managedApplicationToContacts 记录中拉出来。

@Transient
public Set<ManagedApplication> getManagedApplications() {
    if (this.managedApplications.isEmpty()) {
        this.managedApplications = this.managedApplicationToContacts.stream()
                .map(ManagedApplicationToContact::getManagedApplication)
                .collect(Collectors.toSet());
    }
    return this.managedApplications;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-06-17
    • 2019-03-17
    • 1970-01-01
    • 1970-01-01
    • 2022-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多