我们有一个像这样的命名查询:
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遵守这些限制?我应该使用更好的查询吗?
答案 0 :(得分: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”是主键(或至少是唯一标识符)。
答案 1 :(得分:1)
找到答案。看起来EclipseLink必须处理MySQL的这种情况,它也有类似的问题。
答案是在InformixPlatform
子类中,您需要覆盖以下方法来解决此问题:
supportsLocalTemporaryTables()
:这需要返回true
shouldAlwaysUseTempStorageForModifyAll()
:这需要返回true
dontBindUpdateAllQueryUsingTempTables
需要返回true
getCreateTempTableSqlPrefix()
:这需要返回CREATE TEMP TABLE
getCreateTempTableSqlSuffix()
:这需要返回
WITH NO LOG
isInformixOuterJoin()
:需要返回false
getTempTableForTable(DatabaseTable)
:这需要这样做:
return new DatabaseTable("TL_" + table.getName(), "" /* no table qualifier */, table.shouldUseDelimiters(), this.getStartDelimiter(), this.getEndDelimiter());
此外,您还需要覆盖以下方法以及正确的InformixPlatform
行为:
appendBoolean(Boolean, Writer)
:库存Informix平台没有正确写出布尔文字。你需要这样做:
if (Boolean.TRUE.equals(booleanValue)) {
writer.write("'t'");
} else {
writer.write("'f'");
}
您需要覆盖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很高兴。