【问题标题】:SQLServerException when persisting entity - index is out of range持久化实体时出现 SQLServerException - 索引超出范围
【发布时间】:2015-07-16 12:43:42
【问题描述】:

我在持久化具有@OneToOne 关系的实体与另一个实体时遇到问题。我们最近使用 Spring 4 和 Hibernate 4 升级到 Java 8,所以我确信有一些注释或配置发生了变化。

相关代码

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

堆栈跟踪

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

如您所见,PermitState 实体既有与 Permit 的关系(通过 PERMITID,它是 Permit 中的 PK),又有一个名为 PermitId 的字段,它应该与连接的 Permit 的 ID 相关。但这似乎不起作用,它似乎正在尝试插入所有 6 个属性,即使不应将 Permit 插入数据库。我尝试使用@Transient 在 PermitState 中对 Permit 进行注释,但随后出现 AnnotationException:

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

任何帮助将不胜感激!

更新 澄清一下,数据库只有 5 个字段——OID、PERMITID、INVOICED、USED 和 ORDERED——这就是为什么我认为它也尝试插入 Permit 实体的原因。当我们使用 Java 7、Spring 3、hibernate-annotations 3.3.1.GA 和 hibernate-entitymanager 3.3.2.GA 时,完全相同的代码无需修改即可工作。我们现在使用 Java 8、Spring 4 和 Hibernate core+entitymanager+ehcache 4.2.19。

【问题讨论】:

  • 我还发现 PERMITID 在两个地方用作列名。在 permitState 中作为 PERMITID 以及映射。
  • 不,数据库只有 5 个字段,因为不应保留 Permit。只有从 Permit.permitid 派生的 PermitId 应该被持久化。在 Java/Spring/Hibernate 升级之前,此代码也可以正常工作。
  • Permit 作为一个对象不会被持久化在你的情况下 Permit PermitState 这是一个双向关系,当你在这种情况下在 Permit 上指定 @OneToOne (mappedBy) 所以它会在 PermitState 表中创建一个与 Permit 映射的 FK。现在是什么问题你已经指定了@JoinColumn 然后名称是 PERMITID 并且在 @ID 和 @Column 上的名称是 PERMITID

标签: java spring hibernate jpa orm


【解决方案1】:

在我看来,从例外情况来看,您尝试了@Transient,同时仍然拥有@OneToOne 和@JoinColumn。这实际上没有任何意义,因为您告诉 Hibernate 您想自己处理它并且它也应该处理它。

另外,我发现您在 PermitState 中都有 Permit 实体和 permitId 有点令人困惑。你告诉它你不想更新permitId,但你仍然将它用作连接列?

我建议删除 permitId,并且只在 PermitState 中包含 Permit 实体。如果您愿意,您仍然可以使用 getPermitId 方法,但将其视为聚合。

如果所有其他方法都失败,请尝试记录 Hibernate 生成的 SQL 以查看发生了什么。或许贴出来让我们看看。

【讨论】:

  • 您好,谢谢您的回复。我同意同时拥有 Permit 和 PermitId 似乎很奇怪(维护旧代码可能会令人沮丧......)。我试图删除 PermitId 并且在 PermitState 中只有 Permit 实体。但是,我无法更改数据库,所以我仍然需要将 PermitId(即 Permit 实体的 PK)保存在 PermitState 中。这是一个简单的 UML 图,显示了我对它的设想i.imgur.com/uq9dhNh.png。关于我如何实现这一目标的任何帮助?
  • 我在 Permit.java 中的 permitState 属性上使用 @OneToOne(mappedBy = "permit") 和在 PermitState.java 中的 permit 上使用 @OneToOne, @JoinColumn(name = "PERMITID") 解决了这个问题。请看下面我的回答。感谢您的帮助!
【解决方案2】:

我想我解决了。我仍然不完全确定为什么会这样,但确实如此:

我从 PermitState.java 中删除了 PermitId(String 属性),而是使用了 PermitState 中 Permit 实体中的 PermitId。

看起来像这样:

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

感谢马丁和比尔博的帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-17
    • 1970-01-01
    • 2020-09-04
    • 2012-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多