JOOQ:方言 DEFAULT 不支持类型 class org.jooq.impl.SelectImpl
JOOQ: Type class org.jooq.impl.SelectImpl is not supported in dialect DEFAULT
我关于在 jooq dsl 中编写查询的问题。
我在 Oracle 数据库中存储了一些客户端属性列表。
Table结构如下:
CLIENT_ATTRIBUTE_DICT
(ID, CODE, DEFAULT_VALUE) - 所有可能属性的列表
CLIENT_ATTRIBUTE
(ATTRIBUTE_ID, CLIENT_ID, VALUE) - 不同客户端的属性值
我正在尝试 select 给定客户端的所有现有属性(字典中)的值:
如果 CLIENT_ATTRIBUTE 中存在具有给定 clientId 的行而不是属性值 = CLIENT_ATTRIBUTE.VALUE
否则 CLIENT_ATTRIBUTE_DICT.DEFAULT_VALUE
我在 SQL 中的查询(工作正常):
SELECT d.code,
NVL
(
(
SELECT value
FROM CLIENT_ATTRIBUTE a
WHERE a.ATTRIBUTE_ID = d.id
AND a.CLIENT_ID = 1
),
(
SELECT DEFAULT_VALUE
FROM CLIENT_ATTRIBUTE_DICT dd
WHERE dd.id=d.id
)
) value
FROM CLIENT_ATTRIBUTE_DICT d;
我在 Jooq dsl 中的查询:
ClientAttributeDictTable dict = CLIENT_ATTRIBUTE_DICT.as("d");
Map<String, String> attributes =
dsl.select(
dict.CODE,
DSL.nvl(
dsl.select(CLIENT_ATTRIBUTE.VALUE)
.from(CLIENT_ATTRIBUTE)
.where(
CLIENT_ATTRIBUTE.ATTRIBUTE_ID.eq(dict.ID),
CLIENT_ATTRIBUTE.CLIENT_ID.eq(clientId)
),
dsl.select(CLIENT_ATTRIBUTE_DICT.DEFAULT_VALUE)
.from(CLIENT_ATTRIBUTE_DICT)
.where(CLIENT_ATTRIBUTE_DICT.ID.eq(dict.ID))
).as("value")
).from(dict)
.fetchMap(String.class, String.class);
当 jooq 查询运行时失败并显示错误消息:
Caused by: Type class org.jooq.impl.SelectImpl is not supported in dialect DEFAULT
at org.jooq.impl.DefaultDataType.getDataType(DefaultDataType.java:757) ~[na:na]
at org.jooq.impl.DefaultDataType.getDataType(DefaultDataType.java:704) ~[na:na]
at org.jooq.impl.DSL.getDataType(DSL.java:14378) ~[na:na]
at org.jooq.impl.DSL.val(DSL.java:12766) ~[na:na]
at org.jooq.impl.Utils.field(Utils.java:802) ~[na:na]
at org.jooq.impl.DSL.nvl(DSL.java:8403) ~[na:na]
我做错了什么?
UPD
JOOQ版本3.7.2
我找到了解决方法。
首先我重写了 SQL 查询:
SELECT D.CODE, NVL(S.VALUE, D.DEFAULT_VALUE) ATTRIBUTE_VALUE
FROM CLIENT_ATTRIBUTE_DICT D
LEFT JOIN
(SELECT DD.ID,
A.VALUE
FROM CLIENT_ATTRIBUTE_DICT DD
JOIN CLIENT_ATTRIBUTE A
ON A.ATTRIBUTE_ID = DD.ID
WHERE A.CLIENT_ID = 1
) S ON S.ID = D.ID;
比起我在 JOOQ dsl 中表达我的查询:
String ID_FIELD_NAME = "ID";
String VALUE_FIELD_NAME = "VALUE"
ClientAttributeDictTable DICT_ATTRIBUTES = CLIENT_ATTRIBUTE_DICT.as("D");
Table<Record2<Long, String>> EXISTING_ATTRIBUTES =
dsl.select(CLIENT_ATTRIBUTE_DICT.ID, CLIENT_ATTRIBUTE.VALUE)
.from(CLIENT_ATTRIBUTE_DICT)
.join(CLIENT_ATTRIBUTE)
.on(CLIENT_ATTRIBUTE.ATTRIBUTE_ID.eq(CLIENT_ATTRIBUTE_DICT.ID))
.where(CLIENT_ATTRIBUTE.CLIENT_ID.eq(clientId))
.asTable("S", ID_FIELD_NAME, VALUE_FIELD_NAME);
Field<String> ATTRIBUTE_VALUE_FIELD =
nvl(
EXISTING_ATTRIBUTES.field(VALUE_FIELD_NAME, String.class),
DICT_ATTRIBUTES.DEFAULT_VALUE
).as("ATTRIBUTE_VALUE");
Map<String,String> attributes =
dsl.select(DICT_ATTRIBUTES.CODE, ATTRIBUTE_VALUE_FIELD)
.from(DICT_ATTRIBUTES)
.leftJoin(EXISTING_ATTRIBUTES)
.on(DICT_ATTRIBUTES.ID
.eq(EXISTING_ATTRIBUTES.field(ID_FIELD_NAME, Long.class))
)
.fetchMap(DICT_ATTRIBUTES.CODE, ATTRIBUTE_VALUE_FIELD);
在日志中,我发现 JOOK 生成的 SQL 查询发生了一点变化:
SELECT D.CODE,
NVL(S.VALUE, D.DEFAULT_VALUE) ATTRIBUTE_VALUE
FROM CLIENT_ATTRIBUTE_DICT D
LEFT OUTER JOIN (
(SELECT NULL ID, NULL VALUE FROM dual WHERE 1 = 0
)
UNION ALL
(SELECT CLIENT_ATTRIBUTE_DICT.ID,
CLIENT_ATTRIBUTE.VALUE
FROM CLIENT_ATTRIBUTE_DICT
JOIN CLIENT_ATTRIBUTE
ON CLIENT_ATTRIBUTE.ATTRIBUTE_ID = CLIENT_ATTRIBUTE_DICT.ID
WHERE CLIENT_ATTRIBUTE.CLIENT_ID = 141
)
) S ON D.ID = S.ID;
感谢任何改进我的解决方法的想法。
错误有两方面。
您的 API 用法目前不受支持(jOOQ 目前不接受 nvl()
函数中的 Select
类型)。改为这样写:
DSL.nvl(
DSL.field(dsl.select(CLIENT_ATTRIBUTE.VALUE)
// ^^^^^^^^^ explicitly wrap the Select in a Field
.from(CLIENT_ATTRIBUTE)
.where(
CLIENT_ATTRIBUTE.ATTRIBUTE_ID.eq(dict.ID),
CLIENT_ATTRIBUTE.CLIENT_ID.eq(clientId))),
DSL.field(dsl.select(CLIENT_ATTRIBUTE_DICT.DEFAULT_VALUE)
// ^^^^^^^^^ explicitly wrap the Select in a Field
.from(CLIENT_ATTRIBUTE_DICT)
.where(CLIENT_ATTRIBUTE_DICT.ID.eq(dict.ID)))
).as("value")
jOOQ(或者更确切地说,Java 编译器)无法检测到这种 API 误用,因为 nvl()
API 在某种程度上被重载了总是编译。这是一个问题 https://github.com/jOOQ/jOOQ/issues/5340,将在未来的版本中修复(可能是 jOOQ 3.9)
我关于在 jooq dsl 中编写查询的问题。
我在 Oracle 数据库中存储了一些客户端属性列表。
Table结构如下:
CLIENT_ATTRIBUTE_DICT
(ID, CODE, DEFAULT_VALUE) - 所有可能属性的列表CLIENT_ATTRIBUTE
(ATTRIBUTE_ID, CLIENT_ID, VALUE) - 不同客户端的属性值
我正在尝试 select 给定客户端的所有现有属性(字典中)的值:
如果 CLIENT_ATTRIBUTE 中存在具有给定 clientId 的行而不是属性值 = CLIENT_ATTRIBUTE.VALUE
否则 CLIENT_ATTRIBUTE_DICT.DEFAULT_VALUE
我在 SQL 中的查询(工作正常):
SELECT d.code,
NVL
(
(
SELECT value
FROM CLIENT_ATTRIBUTE a
WHERE a.ATTRIBUTE_ID = d.id
AND a.CLIENT_ID = 1
),
(
SELECT DEFAULT_VALUE
FROM CLIENT_ATTRIBUTE_DICT dd
WHERE dd.id=d.id
)
) value
FROM CLIENT_ATTRIBUTE_DICT d;
我在 Jooq dsl 中的查询:
ClientAttributeDictTable dict = CLIENT_ATTRIBUTE_DICT.as("d");
Map<String, String> attributes =
dsl.select(
dict.CODE,
DSL.nvl(
dsl.select(CLIENT_ATTRIBUTE.VALUE)
.from(CLIENT_ATTRIBUTE)
.where(
CLIENT_ATTRIBUTE.ATTRIBUTE_ID.eq(dict.ID),
CLIENT_ATTRIBUTE.CLIENT_ID.eq(clientId)
),
dsl.select(CLIENT_ATTRIBUTE_DICT.DEFAULT_VALUE)
.from(CLIENT_ATTRIBUTE_DICT)
.where(CLIENT_ATTRIBUTE_DICT.ID.eq(dict.ID))
).as("value")
).from(dict)
.fetchMap(String.class, String.class);
当 jooq 查询运行时失败并显示错误消息:
Caused by: Type class org.jooq.impl.SelectImpl is not supported in dialect DEFAULT
at org.jooq.impl.DefaultDataType.getDataType(DefaultDataType.java:757) ~[na:na]
at org.jooq.impl.DefaultDataType.getDataType(DefaultDataType.java:704) ~[na:na]
at org.jooq.impl.DSL.getDataType(DSL.java:14378) ~[na:na]
at org.jooq.impl.DSL.val(DSL.java:12766) ~[na:na]
at org.jooq.impl.Utils.field(Utils.java:802) ~[na:na]
at org.jooq.impl.DSL.nvl(DSL.java:8403) ~[na:na]
我做错了什么?
UPD JOOQ版本3.7.2
我找到了解决方法。
首先我重写了 SQL 查询:
SELECT D.CODE, NVL(S.VALUE, D.DEFAULT_VALUE) ATTRIBUTE_VALUE
FROM CLIENT_ATTRIBUTE_DICT D
LEFT JOIN
(SELECT DD.ID,
A.VALUE
FROM CLIENT_ATTRIBUTE_DICT DD
JOIN CLIENT_ATTRIBUTE A
ON A.ATTRIBUTE_ID = DD.ID
WHERE A.CLIENT_ID = 1
) S ON S.ID = D.ID;
比起我在 JOOQ dsl 中表达我的查询:
String ID_FIELD_NAME = "ID";
String VALUE_FIELD_NAME = "VALUE"
ClientAttributeDictTable DICT_ATTRIBUTES = CLIENT_ATTRIBUTE_DICT.as("D");
Table<Record2<Long, String>> EXISTING_ATTRIBUTES =
dsl.select(CLIENT_ATTRIBUTE_DICT.ID, CLIENT_ATTRIBUTE.VALUE)
.from(CLIENT_ATTRIBUTE_DICT)
.join(CLIENT_ATTRIBUTE)
.on(CLIENT_ATTRIBUTE.ATTRIBUTE_ID.eq(CLIENT_ATTRIBUTE_DICT.ID))
.where(CLIENT_ATTRIBUTE.CLIENT_ID.eq(clientId))
.asTable("S", ID_FIELD_NAME, VALUE_FIELD_NAME);
Field<String> ATTRIBUTE_VALUE_FIELD =
nvl(
EXISTING_ATTRIBUTES.field(VALUE_FIELD_NAME, String.class),
DICT_ATTRIBUTES.DEFAULT_VALUE
).as("ATTRIBUTE_VALUE");
Map<String,String> attributes =
dsl.select(DICT_ATTRIBUTES.CODE, ATTRIBUTE_VALUE_FIELD)
.from(DICT_ATTRIBUTES)
.leftJoin(EXISTING_ATTRIBUTES)
.on(DICT_ATTRIBUTES.ID
.eq(EXISTING_ATTRIBUTES.field(ID_FIELD_NAME, Long.class))
)
.fetchMap(DICT_ATTRIBUTES.CODE, ATTRIBUTE_VALUE_FIELD);
在日志中,我发现 JOOK 生成的 SQL 查询发生了一点变化:
SELECT D.CODE,
NVL(S.VALUE, D.DEFAULT_VALUE) ATTRIBUTE_VALUE
FROM CLIENT_ATTRIBUTE_DICT D
LEFT OUTER JOIN (
(SELECT NULL ID, NULL VALUE FROM dual WHERE 1 = 0
)
UNION ALL
(SELECT CLIENT_ATTRIBUTE_DICT.ID,
CLIENT_ATTRIBUTE.VALUE
FROM CLIENT_ATTRIBUTE_DICT
JOIN CLIENT_ATTRIBUTE
ON CLIENT_ATTRIBUTE.ATTRIBUTE_ID = CLIENT_ATTRIBUTE_DICT.ID
WHERE CLIENT_ATTRIBUTE.CLIENT_ID = 141
)
) S ON D.ID = S.ID;
感谢任何改进我的解决方法的想法。
错误有两方面。
您的 API 用法目前不受支持(jOOQ 目前不接受
nvl()
函数中的Select
类型)。改为这样写:DSL.nvl( DSL.field(dsl.select(CLIENT_ATTRIBUTE.VALUE) // ^^^^^^^^^ explicitly wrap the Select in a Field .from(CLIENT_ATTRIBUTE) .where( CLIENT_ATTRIBUTE.ATTRIBUTE_ID.eq(dict.ID), CLIENT_ATTRIBUTE.CLIENT_ID.eq(clientId))), DSL.field(dsl.select(CLIENT_ATTRIBUTE_DICT.DEFAULT_VALUE) // ^^^^^^^^^ explicitly wrap the Select in a Field .from(CLIENT_ATTRIBUTE_DICT) .where(CLIENT_ATTRIBUTE_DICT.ID.eq(dict.ID))) ).as("value")
jOOQ(或者更确切地说,Java 编译器)无法检测到这种 API 误用,因为
nvl()
API 在某种程度上被重载了总是编译。这是一个问题 https://github.com/jOOQ/jOOQ/issues/5340,将在未来的版本中修复(可能是 jOOQ 3.9)