kirill_antv
kirill_antv

Reputation: 49

Hibernate throws the column index is out of range expection while saving entity with composite primary key

I've met with a very strange Hibernate's behaviour, or maybe I don't know something. My Hibernate version is 5.4.12.

When I try to save entity with composite primary key Hibernate binds 5th parameter while I have only 4. I had been trying to solve this problem for few days and I had no result.

This is the trouble entity:

@Entity
@Table(name = "asset_asset_type_attribute")
@Getter
@Setter
@IdClass(AssetAttributeId.class)
public class AssetAssetTypeAttribute {

    @Id
    @Column(name = "tenant_id", insertable = false, updatable = false)
    private Long tenantId;

    @Id
    @Column(name = "asset_id", insertable = false, updatable = false)
    private Long assetId;

    @Id
    @Column(name = "asset_type_attribute_id")
    private Long assetTypeAttributeId;

    @Id
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumns({
            @JoinColumn(name = "asset_id", referencedColumnName = "id"),
            @JoinColumn(name = "tenant_id", referencedColumnName = "tenant_id"),
    })
    @JsonIgnore
    private Asset asset;

    @Id
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "asset_type_attribute_id", referencedColumnName = "id", insertable = false, updatable = false)
    private AssetTypeAttribute assetTypeAttribute;

    private String value;
}

@Data
@AllArgsConstructor
@NoArgsConstructor
public class AssetAttributeId implements Serializable {
    private Long assetId;
    private Long assetTypeAttributeId;
    private Long tenantId;
}

The other related entities:

@Entity
@Table(name = "asset")
@Getter
@Setter
@IdClass(AssetId.class)
public class Asset {
    @Id
    private Long id;
    
    @Id
    @Column(name = "tenant_id")
    private Long tenantId;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "asset", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<AssetAssetTypeAttribute> assetAssetTypeAttributes;
}

@Data
@NoArgsConstructor
@AllArgsConstructor
public class AssetId implements Serializable {
    private Long id;
    private Long tenantId;
}



@Entity
@Table(name = "asset_type_attribute")
@Getter
@Setter
public class AssetTypeAttribute {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "assetTypeAttribute", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<AssetAssetTypeAttribute> assetAssetTypeAttributes;
}

This is the way I put AssetAssetTypeAttribute in Asset Entity

AssetAssetTypeAttribute assetAssetTypeAttribute = new AssetAssetTypeAttribute();

assetAssetTypeAttribute.setAssetTypeAttribute(assetTypeAttribute);
assetAssetTypeAttribute.setAsset(asset);
assetAssetTypeAttribute.setValue(entry.getValue());
asset.getAssetAssetTypeAttributes().add(assetAssetTypeAttribute);

This is the way I save entities:

Session session = sessionFactory.openSession();
session.setHibernateFlushMode(FlushMode.COMMIT);
Transaction transaction = session.beginTransaction();

try {
    session.saveOrUpdate(asset);
    for (AssetAssetTypeAttribute assetTypeAttribute : asset.getAssetAssetTypeAttributes()) {
        session.saveOrUpdate(assetTypeAttribute);
    }

    transaction.commit();
    return asset;
} catch (Exception e) {
    transaction.rollback();
    throw e;
} finally {
    session.close();
}

When Hibernate tries to save AssetAssetTypeAttribute entity, it generate this stuff:

2020-11-19 02:49:01,250 DEBUG [http-nio-8080-exec-7] org.hibernate.engine.jdbc.spi.SqlStatementLogger: insert into asset_asset_type_attribute (asset_id, tenant_id, value, asset_type_attribute_id) values (?, ?, ?, ?)
2020-11-19 02:49:01,250 TRACE [http-nio-8080-exec-7] org.hibernate.type.descriptor.sql.BasicBinder: binding parameter [1] as [BIGINT] - [57]
2020-11-19 02:49:01,251 TRACE [http-nio-8080-exec-7] org.hibernate.type.descriptor.sql.BasicBinder: binding parameter [2] as [BIGINT] - [1]
2020-11-19 02:49:01,251 TRACE [http-nio-8080-exec-7] org.hibernate.type.descriptor.sql.BasicBinder: binding parameter [3] as [VARCHAR] - [231]
2020-11-19 02:49:01,251 TRACE [http-nio-8080-exec-7] org.hibernate.type.descriptor.sql.BasicBinder: binding parameter [4] as [BIGINT] - [null]
2020-11-19 02:49:01,251 TRACE [http-nio-8080-exec-7] org.hibernate.type.descriptor.sql.BasicBinder: binding parameter [5] as [BIGINT] - [1]

And therefore I got this exception on the Postgresql level:

javax.persistence.PersistenceException: org.hibernate.exception.DataException: could not insert: [com.bitraid.servicedesk.entity.AssetAssetTypeAttribute]
    at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:154)
    at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:181)
    at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:188)
    at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1356)
    at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:443)
    at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3202)
    at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2370)
    at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:447)
    at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:183)
    at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$300(JdbcResourceLocalTransactionCoordinatorImpl.java:40)
    at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:281)
    at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:101)
    at com.bitraid.servicedesk.service.impl.AssetServiceImpl.saveAsset(AssetServiceImpl.java:245)
    at com.bitraid.servicedesk.service.impl.AssetServiceImpl.create(AssetServiceImpl.java:102)
    at com.bitraid.servicedesk.controllers.AssetController.create(AssetController.java:27)
    at com.bitraid.servicedesk.controllers.AssetController$$FastClassBySpringCGLIB$$9d47bc91.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
    at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:69)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691)
    at com.bitraid.servicedesk.controllers.AssetController$$EnhancerBySpringCGLIB$$7255f121.create(<generated>)
    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:498)
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:879)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:660)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at com.bitraid.servicedesk.security.JwtTokenFilter.doFilter(JwtTokenFilter.java:35)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:320)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:126)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:90)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:118)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:158)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at com.bitraid.servicedesk.security.JwtTokenFilter.doFilter(JwtTokenFilter.java:35)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:92)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:77)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:373)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1594)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:748)
Caused by: org.hibernate.exception.DataException: could not insert: [com.bitraid.servicedesk.entity.AssetAssetTypeAttribute]
    at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:115)
    at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3253)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3760)
    at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:107)
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604)
    at org.hibernate.engine.spi.ActionQueue.lambda$executeActions$1(ActionQueue.java:478)
    at java.util.LinkedHashMap.forEach(LinkedHashMap.java:684)
    at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:475)
    at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:348)
    at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:40)
    at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:102)
    at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1352)
    ... 107 more
Caused by: org.postgresql.util.PSQLException: The column index is out of range: 5, number of columns: 4.
    at org.postgresql.core.v3.SimpleParameterList.bind(SimpleParameterList.java:65)
    at org.postgresql.core.v3.SimpleParameterList.setBinaryParameter(SimpleParameterList.java:132)
    at org.postgresql.jdbc.PgPreparedStatement.bindBytes(PgPreparedStatement.java:1012)
    at org.postgresql.jdbc.PgPreparedStatement.setLong(PgPreparedStatement.java:302)
    at org.apache.commons.dbcp2.DelegatingPreparedStatement.setLong(DelegatingPreparedStatement.java:428)
    at org.apache.commons.dbcp2.DelegatingPreparedStatement.setLong(DelegatingPreparedStatement.java:428)
    at org.hibernate.type.descriptor.sql.BigIntTypeDescriptor$1.doBind(BigIntTypeDescriptor.java:46)
    at org.hibernate.type.descriptor.sql.BasicBinder.bind(BasicBinder.java:73)
    at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:276)
    at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:271)
    at org.hibernate.type.ComponentType.nullSafeSet(ComponentType.java:340)
    at org.hibernate.persister.entity.AbstractEntityPersister.dehydrateId(AbstractEntityPersister.java:2977)
    at org.hibernate.persister.entity.AbstractEntityPersister.dehydrate(AbstractEntityPersister.java:2935)
    at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3226)
    ... 117 more

Sorry for the long read. But I tried to describe the problem in more detail. I would be grateful for any help.

Upvotes: 3

Views: 1315

Answers (2)

kirill_antv
kirill_antv

Reputation: 49

Issue in JIRA - https://hibernate.atlassian.net/browse/HHH-14340. And seems like I found workaround with @Embeddable annotation.

@Entity
@Table(name = "asset")
public class Asset {

    @EmbeddedId
    private AssetId assetPK;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "id.asset", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<AssetAssetTypeAttribute> assetAssetTypeAttributes;

    /* getters, setters and etc... */
}

@Embeddable
public class AssetId implements Serializable {
    private Long id;
    @Column(name = "tenant_id")
    private Long tenantId;

    /* getters, setters and etc... */
}

@Entity
@Table(name = "asset_asset_type_attribute")
public class AssetAssetTypeAttribute {

    @EmbeddedId
    private AssetAttributeId id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "asset_type_attribute_id", referencedColumnName = "id", insertable = false, updatable = false)
    private AssetTypeAttribute assetTypeAttribute;

    private String value;

   /* getters, setters and etc... */
}

@Embeddable
public class AssetAttributeId implements Serializable {

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumns({
            @JoinColumn(name = "asset_id", referencedColumnName = "id"),
            @JoinColumn(name = "tenant_id", referencedColumnName = "tenant_id"),
    })
    private Asset asset;
    private Long assetTypeAttributeId;
    
    /* getters, setters and etc... */
}

Upvotes: 2

Christian Beikov
Christian Beikov

Reputation: 16400

Have you tried using the following yet?

@Id
@Column(name = "asset_type_attribute_id", insertable = false, updatable = false)
private Long assetTypeAttributeId;

I think it might pose a problem that you list this attribute in the id class already.

Could you try updating Hibernate to the latest version 5.4.24? If the problem still remains, please create an issue in the issue tracker(https://hibernate.atlassian.net) with a test case(https://github.com/hibernate/hibernate-test-case-templates/blob/master/orm/hibernate-orm-5/src/test/java/org/hibernate/bugs/JPAUnitTestCase.java) that reproduces the issue.

Upvotes: 0

Related Questions