2012-11-08 62 views
1

我有一個簡單的實體(一些無關緊要的領域中省略爲簡潔起見):通過設置trueinitializationInProgress的EclipseLink 2.3.3無法更新版本實體上的PostgreSQL

@Entity 
@Table(name = "tenant") 
public class Tenant { 

    @Id 
    private String id; 

    @Version @Column 
    private long version = 0; 

    @Column(name = "init_in_progress") 
    private Boolean initializationInProgress; 

} 

我想要做的所有租戶批量更新使用JPA更新查詢是這樣的:

entityManager.createQuery(
      "UPDATE Tenant t " + 
      "SET t.initializationInProgress = :ip") 
     .setParameter("ip", initializationInProgress) 
     .executeUpdate(); 

這正常工作與EclipseLink 2.2.1。但是,當我嘗試用2.3.3版本一樣,然後我得到一個錯誤:

Caused by: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.3.3.v20120629-r11760): org.eclipse.persistence.exceptions.DatabaseException 
Internal Exception: org.postgresql.util.PSQLException: ERROR: more than one row returned by a subquery used as an expression 
Error Code: 0 
Call: UPDATE tenant SET version = (SELECT (version + ?) FROM tenant WHERE ID = tenant.ID), init_in_progress = ? 
    bind => [1, true] 
Query: UpdateAllQuery(referenceClass=Tenant sql="UPDATE tenant SET version = (SELECT (version + ?) FROM tenant WHERE ID = tenant.ID), init_in_progress = ?") 
    at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:333) 
    at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.processExceptionForCommError(DatabaseAccessor.java:1494) 
    at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:838) 
    at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeNoSelect(DatabaseAccessor.java:906) 
    at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:592) 
    at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeCall(DatabaseAccessor.java:535) 
    at org.eclipse.persistence.internal.sessions.AbstractSession.basicExecuteCall(AbstractSession.java:1717) 
    at org.eclipse.persistence.sessions.server.ClientSession.executeCall(ClientSession.java:253) 
    at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:207) 
    at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:193) 
    at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeNoSelectCall(DatasourceCallQueryMechanism.java:236) 
    at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.updateAll(DatasourceCallQueryMechanism.java:789) 
    at org.eclipse.persistence.queries.UpdateAllQuery.executeDatabaseQuery(UpdateAllQuery.java:153) 
    at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:844) 
    at org.eclipse.persistence.queries.DatabaseQuery.executeInUnitOfWork(DatabaseQuery.java:743) 
    at org.eclipse.persistence.queries.ModifyAllQuery.executeInUnitOfWork(ModifyAllQuery.java:145) 
    at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2871) 
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1516) 
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1498) 
    at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1463) 
    at org.eclipse.persistence.internal.jpa.EJBQueryImpl.executeUpdate(EJBQueryImpl.java:540) 
    at com.example.dao.impl.tenant.TenantRepositoryImpl.updateAllTenantsInitializationStatus(TenantRepositoryImpl.java:100) 

是任何人都熟悉這個bug?任何已知的解決方法/修復(除了不改變EclipseLink版本)?感謝你的幫助。我正在使用PostgreSQL 9.1

回答

1

最初看起來像一個數據問題,在tenant中您有多個具有相同ID的行,但實際上這是EclipseLink查詢的問題。由於這是一個生成的查詢,因此您似乎手上有(嚴重的)EclipseLink錯誤。

更新:請參閱this EclipseLink bugzilla entry for bug 393223

查詢應真正別名內部參考tenant,如:

UPDATE tenant SET version = (SELECT (t2.version + ?) FROM tenant t2 WHERE t2.ID = tenant.ID), init_in_progress = ? 

未能添加此別名意味着ID = tenant.ID意味着tenant.ID = tenant.ID ...這始終是真實的,所以子查詢匹配的tenant每一行。

觀察這個演示:

CREATE TABLE tenant (ID integer primary key, version integer); 
INSERT INTO tenant (id, version) values (1,0), (2,0), (3,0); 

BEGIN; 

PREPARE testq(integer) AS 
UPDATE tenant SET version = (SELECT (version + $1) FROM tenant WHERE ID = tenant.ID); 

regress=> EXECUTE testq(1); 
ERROR: more than one row returned by a subquery used as an expression 

ROLLBACK; 

更正查詢:

BEGIN; 

PREPARE testq2(integer) AS 
UPDATE tenant SET version = (SELECT (version + $1) FROM tenant t2 WHERE t2.ID = tenant.ID); 

regress=> EXECUTE testq2(1); 
UPDATE 3 

ROLLBACK; 

這似乎是一個的EclipseLink錯誤。我沒有看到你可以在代碼中做很多事情,除了作爲原生SQL進行批量更新之外。

+0

@ madth3反正我錯了;回答修改。 –

+0

它看起來像一個,但對我來說,但我找不到錯誤報告,所以我認爲,也許我做錯了,因爲這個錯誤似乎真的很重要。感謝您在這個話題上的努力。 – Roadrunner