1

我们有一个这样的命名查询:

UPDATE Foo f SET f.x = 0 WHERE f.x = :invoiceId

Foo在这种情况下是具有超类的实体,使用每类表的继承策略。

EclipseLink 生成的 SQL 是:

UPDATE foo_subclass SET x = ?
 WHERE EXISTS(SELECT t0.id
                FROM foo_superclass t0, foo_subclass t1
               WHERE ((t1.x = ?) AND ((t1.id = t0.id) AND (t0.DTYPE = ?)))

?插槽已正确填充。)

在 Informix 11.70 上,我们收到子查询无法访问正在更改的表的错误。

这是我能够找到的关于 Informix 子查询限制的文档:http: //publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp ?topic=%2Fcom.ibm.sqls.doc%2Fids_sqs_2005 .htm

其他数据库也对这样的子查询有限制,因此尽管这表现为 Informix 问题,但我敢肯定,如果我们针对 MySQL 运行它,我们会得到类似的错误。

如何让 EclipseLink 遵守这些限制?我应该使用更好的查询吗?

4

2 回答 2

1

找到了答案。看起来 EclipseLink 必须为 MySQL 处理这种情况,它也有类似的问题。

答案是在你的InformixPlatform子类中,你需要重写以下方法来解决这个问题:

  1. supportsLocalTemporaryTables(): 这需要返回true
  2. shouldAlwaysUseTempStorageForModifyAll(): 这需要返回true
  3. dontBindUpdateAllQueryUsingTempTables需要返回true
  4. getCreateTempTableSqlPrefix(): 这需要返回CREATE TEMP TABLE 
  5. getCreateTempTableSqlSuffix(): 这需要返回 WITH NO LOG
  6. isInformixOuterJoin(): 需要退货false
  7. getTempTableForTable(DatabaseTable):这需要这样做:

    return new DatabaseTable("TL_" + table.getName(), "" /* no table qualifier */, table.shouldUseDelimiters(), this.getStartDelimiter(), this.getEndDelimiter());
    

此外,您还需要覆盖以下方法以获得正确的InformixPlatform行为:

  1. appendBoolean(Boolean, Writer):库存的 Informix 平台无法正确写出布尔文字。你需要这样做:

    if (Boolean.TRUE.equals(booleanValue)) {
      writer.write("'t'");
    } else {
      writer.write("'f'");
    }
    
  2. 您需要覆盖writeUpdateOriginalFromTempTableSql,以便它包含与覆盖相同的代码H2Platform

    @Override
    public void writeUpdateOriginalFromTempTableSql(final Writer writer, final DatabaseTable table, final Collection pkFields, final Collection assignedFields) throws IOException {
      writer.write("UPDATE ");
      final String tableName = table.getQualifiedNameDelimited(this);    
      writer.write(tableName);
      writer.write(" SET ");
      final int size = assignedFields.size();
      if (size > 1) {
        writer.write("(");            
      }
      writeFieldsList(writer, assignedFields, this);
      if (size > 1) {
        writer.write(")");            
      }
      writer.write(" = (SELECT ");        
      writeFieldsList(writer, assignedFields, this);
      writer.write(" FROM ");
      final String tempTableName = this.getTempTableForTable(table).getQualifiedNameDelimited(this);
      writer.write(tempTableName);
      writeAutoJoinWhereClause(writer, null, tableName, pkFields, this);
      writer.write(") WHERE EXISTS(SELECT ");
      writer.write(((DatabaseField)pkFields.iterator().next()).getNameDelimited(this));
      writer.write(" FROM ");
      writer.write(tempTableName);
      writeAutoJoinWhereClause(writer, null, tableName, pkFields, this);
      writer.write(")");
    }
    

最后,您的构造函数需要调用this.setShouldBindLiterals(false).

有了这些变化,Informix 似乎很高兴。

于 2013-03-01T04:34:02.460 回答
1

代替:

UPDATE foo_subclass SET x = ?
 WHERE EXISTS(SELECT t0.id
                FROM foo_superclass t0, foo_subclass t1
               WHERE ((t1.x = ?) AND ((t1.id = t0.id) AND (t0.DTYPE = ?)))

做这个:

UPDATE
  foo_subclass SET x = ?
WHERE
  foo_subclass.x = ? AND
  EXISTS(SELECT t0.id
         FROM foo_superclass t0
         WHERE ((foo_subclass.id = t0.id) AND (t0.DTYPE = ?))

请注意,在 11.50 上,您不能为 foo_subclass 使用别名。11.70 允许。我假设“id”是主键(或至少是唯一标识符)。

于 2013-02-27T22:33:20.557 回答