问题描述:

I'm having problems persisting an entity with a @OneToOne relationship with another entity. We've recently upgraded to Java 8 with Spring 4 and Hibernate 4 so I'm sure there's some annotation or configuration that has changed.

Relevant code

PermitState.java:

@Entity

@Table(schema = "dbo", name = "PermitState")

public class PermitState implements Serializable {

private String oid;

private Permit permit;

private Integer invoiced;

private Integer used;

private Integer ordered;

private String permitId;

@OneToOne(fetch = FetchType.LAZY)

@JoinColumn(name = "PERMITID")

public Permit getPermit() {

return permit;

}

@Id

@Column(name = "PERMITID", nullable = true, length = 8,insertable = false,updatable = false)

public String getPermitId() {

return permitId;

}

... more getters and setters (irrelevant)

Permit.java:

@Entity

@Table(schema = "dbo")

public class Permit {

private String permitid;

private PermitState permitState;

...some more attributes, irrelevant

@Id

@Column(name = "PERMITID", length = 8)

public String getPermitid() {

return permitid;

}

@OneToOne(mappedBy="permit", cascade=CascadeType.ALL,fetch = FetchType.LAZY)

public PermitState getPermitState() {

return permitState;

}

Stacktrace

Caused by: org.hibernate.exception.GenericJDBCException: could not insert: [dao.srs.model.PermitState]

at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:54)

at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:124)

at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3099)

at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3521)

at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:88)

at org.hibernate.engine.spi.ActionQueue.execute(ActionQueue.java:395)

at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:387)

at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:303)

at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:349)

at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:56)

at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1195)

at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:404)

at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)

at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:175)

at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:75)

at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:515)

... 65 more

Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: The index 6 is out of range.

at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDriverError(SQLServerException.java:171)

at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.setterGetParam(SQLServerPreparedStatement.java:700)

at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.setValue(SQLServerPreparedStatement.java:709)

at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.setString(SQLServerPreparedStatement.java:1034)

at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.setString(NewProxyPreparedStatement.java:963)

at org.hibernate.type.descriptor.sql.VarcharTypeDescriptor$1.doBind(VarcharTypeDescriptor.java:57)

at org.hibernate.type.descriptor.sql.BasicBinder.bind(BasicBinder.java:93)

at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:284)

at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:279)

at org.hibernate.type.ComponentType.nullSafeSet(ComponentType.java:343)

at org.hibernate.persister.entity.AbstractEntityPersister.dehydrateId(AbstractEntityPersister.java:2835)

at org.hibernate.persister.entity.AbstractEntityPersister.dehydrate(AbstractEntityPersister.java:2804)

at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3076)

... 78 more

As you can see, the PermitState entity has both a relation to Permit (via PERMITID, which is the PK in Permit) AND a field called PermitId, which is supposed to the connected Permit's ID. This doesn't seem to work though, it seems that it's trying to insert all 6 attributes even though Permit shouldn't be inserted into the database. I tried to annotate Permit in PermitState with @Transient, but then I get a AnnotationException:

Caused by: org.hibernate.AnnotationException: Unknown mappedBy in: dao.srs.model.Permit.permitState, referenced property unknown: dao.srs.model.PermitState.permit

Any help would be greatly appreciated!

Update

Just to clarify, the DB only have 5 fields - OID, PERMITID, INVOICED, USED and ORDERED - which is why I'm thinking its trying to insert the Permit entity as well. The exact same code without modifications worked when we used Java 7, Spring 3, hibernate-annotations 3.3.1.GA and hibernate-entitymanager 3.3.2.GA. We now use Java 8, Spring 4 and Hibernate core+entitymanager+ehcache 4.2.19.

网友答案:

It seem to me, judging from the exception, that you tried @Transient while still having the @OneToOne and @JoinColumn. That does not really make sense, as you tell Hibernate you want to handle it yourself and that it should handle it also.

Also I find it a bit confusing you both have the Permit entity and the permitId in PermitState. You tell it that you don't want to update permitId, but you still use it as the join column?

I recommend removing the permitId and only have the Permit entity in PermitState. You can still have the getPermitId method if you like, but treat it as an agregate instead.

If all else fails try and log the SQL generated by Hibernate to see what is going on. Perhaps pasting it for us to see.

网友答案:

I think I solved it. I'm still not entirely sure why this works, but it does:

I removed PermitId (the String property) from PermitState.java, and instead used the PermitId from the Permit entitiy in PermitState.

It looks like this:

Permit.java:

private String permitid;
private PermitState permitState;

@OneToOne(mappedBy="permit", cascade=CascadeType.ALL,fetch = FetchType.LAZY)
public PermitState getPermitState() {
    return permitState;
}

PermitState.java

private Permit permit;

@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "PERMITID")
public Permit getPermit() {
    return permit;
}

Thanks Martin and Bilbo for your help.

相关阅读:
Top