I'm using jOOQ with Postgresql to select an enum value from a table.
List<my.project.jooq.enums.Color> colors =
dsl.selectDistinct(TABLE.T_COLOR.as("color"))
.from(TABLE).fetch()
.into(my.project.jooq.enums.Color.class);
Anyway I get the exception:
org.jooq.exception.MappingException: No matching constructor found on type class my.project.jooq.enums.Color for record org.jooq.impl.DefaultRecordMapper#7c66447f
I see that fetch() will return Result<Record1<my.project.model.jooq.enums.Color>>, so I wonder if there is a way to immediately fetch the Color enums into a list as I can do with any pojo.
How can I fetch into the enum values?
As of jOOQ 3.7, this is not yet supported out of the box, but will be in jOOQ 3.8 (see #5154).
You can easily map a string column to your Enum type yourself, though, via
List<my.project.jooq.enums.Color> colors =
dsl.selectDistinct(TABLE.T_COLOR)
.from(TABLE)
.fetch()
.map(rec -> my.project.jooq.enums.Color.valueOf(rec.getValue(TABLE.T_COLOR)));
In case, your my.project.jooq.enums.Color was generated by jOOQ from a PostgreSQL enum data type, you don't need to specifically map anything, jOOQ will automatically do that for you:
List<my.project.jooq.enums.Color> colors =
dsl.selectDistinct(TABLE.T_COLOR)
.from(TABLE)
.fetch(TABLE.T_COLOR);
Related
In normal SQL queries to select the particular field (emp_id,emp_name,emp_email) we use
select emp_name from table_name(to display/fetch only emp_name)
In the same way how to do it in hazelcast?
static IMap<String, Model)> map = hazelCast.getMap("data");
map.put(1,(new Model(emp_id,emp_name,emp_email)));
map.values(new SqlPredicate("data[any].entity_id"));
How to select only emp_name values in the result?
What you're looking for is called a Projection in Hazelcast. What is stored in your map are objects of type Map.Entry; anytime you want to return something other than a Map.Entry, you can create a Projection to transform the Entry into the desired return type.
When you need to do a non-trivial transformation, you can implement custom Projections, but there are built-in Projections you can simply reuse when you're just trying to return a single attribute or a set of attributes from the entry.
So in your case, you can use the built-in singleAttribute projection:
Projection empNameProjection = Projection.singleAttribute("emp_name");
And then you can use IMap.project to return the projection for all entries, or for entries matching a predicte:
Collection<String> names = map.project(empNameProjection, mySqlPredicate);
See:
https://docs.hazelcast.org/docs/latest-dev/manual/html-single/#projection-api
I am trying to execute .fetchMap(key, value) with jOOQ but I want to process the key through a custom converter.
The docs are very clear on how to use converters and how to use .fetchMap() but I can't find anywhere a way of combining both.
Could this feature be missing from my jOOQ version (3.9) ?
Converter (and Binding) implementations are bound to the Field reference by the code generator, or you can do it manually like this:
// Using this static import
import static org.jooq.impl.DSL.*;
// Assuming a VARCHAR column in the database:
DataType<MyType> type = SQLDataType.VARCHAR.asConvertedDataType(
new MyConverter<String, MyType>());
Field<MyType> field = field(name("MY_TABLE", "MY_FIELD"), type);
Now, whenever you fetch this field in your SELECT statements, e.g.
Result<Record1<MyType>> result =
DSL.using(configuration)
.select(field)
.from(...)
.fetch();
jOOQ will automatically apply your converter while fetching results from the underlying JDBC ResultSet. You will never see the original String value in your result.
The ResultQuery.fetchMap(Field, Field) method that you've mentioned is just short for fetch() and then Result.intoMap(Field, Field). In other words, the converter will already have been applied automatically by the time you call fetchMap() or intoMap(), so there is no need to do anything specific. Just use your field as an argument to fetchMap() :
Map<MyType, OtherType> result =
DSL.using(configuration)
.select(field, otherField)
.from(...)
.fetchMap(field, otherField);
In jOOQ if I want to fetch a row of a table into a jOOQ autogenerated POJOs I do, for instance:
dsl.selectFrom(USER)
.where(USER.U_EMAIL.equal(email))
.fetchOptionalInto(User.class);
Now, suppose that I want to do a join between two tables, e.g. USER and ROLE, how can I fetch the result into the POJOs for these two tables?
Using nested collections
With more recent versions of jOOQ, you'll typically use a set of ORDBMS features, including:
nested collections using MULTISET
nested records and nested table records
ad-hoc converters
You'll write something like this, to produce jOOQ types:
Result<Record2<UserRecord, Result<Record1<RoleRecord>>>> result =
dsl.select(
USER,
multiset(
selectFrom(USER_ROLE.role())
.where(USER_ROLE.USER_ID.eq(USER.ID))
))
.from(USER)
.where(USER.U_EMAIL.equal(email))
.fetch();
Or, by using said ad-hoc converters, to produce your own types:
List<User> result =
dsl.select(
USER.U_ID,
USER.U_EMAIL,
...
multiset(
selectFrom(USER_ROLE.role())
.where(USER_ROLE.USER_ID.eq(USER.ID))
).convertFrom(r -> r.map(Records.mapping(Role::new))))
.from(USER)
.where(USER.U_EMAIL.equal(email))
.fetch(Records.mapping(User::new));
Historic answers / alternatives
There are other ways to achieve something like the above, for completeness' sake:
Fetching the POJOs into a Map
This is one solution using ResultQuery.fetchGroups(RecordMapper, RecordMapper)
Map<UserPojo, List<RolePojo>> result =
dsl.select(USER.fields())
.select(ROLE.fields())
.from(USER)
.join(USER_TO_ROLE).on(USER.USER_ID.eq(USER_TO_ROLE.USER_ID))
.join(ROLE).on(ROLE.ROLE_ID.eq(USER_TO_ROLE.ROLE_ID))
.where(USER.U_EMAIL.equal(email))
.fetchGroups(
// Map records first into the USER table and then into the key POJO type
r -> r.into(USER).into(UserPojo.class),
// Map records first into the ROLE table and then into the value POJO type
r -> r.into(ROLE).into(RolePojo.class)
);
Note, if you want to use LEFT JOIN instead (in case a user does not necessarily have any roles, and you want to get an empty list per user), you'll have to translate NULL roles to empty lists yourself.
Make sure you have activated generating equals() and hashCode() on your POJOs in order to be able to put them in a HashMap as keys:
<pojosEqualsAndHashCode>true</pojosEqualsAndHashCode>
Using custom, hierarchical POJOs and fetching them into a nested collection
A frequently re-occurring question is how to fetch nested collections in jOOQ, i.e. what if your result data structures look like this:
class User {
long id;
String email;
List<Role> roles;
}
class Role {
long id;
String name;
}
Starting with jOOQ 3.14, and if your RDBMS supports it, you can now use SQL/XML or SQL/JSON as an intermediary format to nest collections, and then use Jackson, Gson, or JAXB to map the document back to your Java classes (or keep the XML or JSON, if that's what you needed in the first place). For example:
List<User> users =
ctx.select(
USER.ID,
USER.EMAIL,
field(
select(jsonArrayAgg(jsonObject(ROLE.ID, ROLE.NAME)))
.from(ROLES)
.join(USER_TO_ROLE).on(ROLE.ROLE_ID.eq(USER_TO_ROLE.ROLE_ID))
.where(USER_TO_ROLE.USER.ID.eq(USER.ID))
).as("roles")
)
.from(USER)
.where(USER.EMAIL.eq(email))
.fetchInto(User.class);
Note that JSON_ARRAYAGG() aggregates empty sets into NULL, not into an empty []. If that's a problem, use COALESCE()
continuing good answer of Lukas Eder:
If you need list structure in return or you can not ovveride equals or hashcode in your POJO you can fetch it into List<Pair>
List<Pair<UserPojo, RolePojo>> result = dsl.select(USER.fields())
.select(ROLE.fields())
.from(USER)
.join(USER_TO_ROLE).on(USER.USER_ID.eq(USER_TO_ROLE.USER_ID))
.join(ROLE).on(ROLE.ROLE_ID.eq(USER_TO_ROLE.ROLE_ID))
.where(USER.U_EMAIL.equal(email))
.fetch(record -> {
UserPojo userPojo = r.into(USER).into(UserPojo.class);
RolePojo rolePojo = r.into(ROLE).into(RolePojo.class);
return new ImmutablePair<>(zoneEntity, userEntity);
});
I've got dsl with POSTGRES_9_4 dialect. I try to use custom selection query with org.jooq.impl.DSL.Condition:
dsl.selectFrom(TAG_JSON).where(condition("translations ??| array[?]", normValues)).fetch(mapper);
It throws an exception:
org.jooq.exception.SQLDialectNotSupportedException: Type class java.util.ArrayList is not supported in dialect DEFAULT
at org.jooq.impl.DefaultDataType.getDataType(DefaultDataType.java:757)
at org.jooq.impl.DefaultDataType.getDataType(DefaultDataType.java:704)
at org.jooq.impl.DSL.getDataType(DSL.java:14371)
at org.jooq.impl.Utils.queryParts(Utils.java:1565)
at org.jooq.impl.SQLImpl.<init>(SQLImpl.java:64)
at org.jooq.impl.DSL.sql(DSL.java:6240)
at org.jooq.impl.DSL.condition(DSL.java:7323)
Why DEFAULT dialect is used? How to configure global one?
The error message is a bit misleading. Your intention seems for array[?] to take a List<String> as a single bind value to pass to an array constructor. This won't work. You have two options:
Binding a single array
condition("translations <op> ?::text[]", normValues.toArray(new String[0]))
Binding the array as a list of bind values
condition("translations <op> {0}", list(
normValues.stream().map(DSL::val).toArray(QueryPart[]::new)
))
This is using DSL.list() to create a list of bind variables.
Note, in both cases, I have avoided your ??| operator because jOOQ parses plain SQL text for bind values (?) and currently doesn't recognise ??| as a non-bind variable sequence (I've registered an issue for this). If that operator has a textual alternative representation, I recommend using that instead.
My backend is postgresql. I am trying to write a simple function to fetch data from database, using jooq records. The DAO for this table is written by me. The problem I am facing is comparison of UUID in db and String provided to function.
public Correspondence fetchByExternalId(String externalId) {
CorrespondenceRecord correspondenceRecord =
create.fetchOne(Tables.CORRESPONDENCE,
Tables.CORRESPONDENCE.USERID.eq(externalId));
CORRESPONDENCE.USERID is UUID and externalId is String; The operator eq is the one which i am not able to implement here, which has worked for me on previous occasions.
The error shown is :
Cannot resolve method 'eq(java.lang.String)'
when i referred to the jOOQ site for help it show 'eq' is the operator it suggests to be used!
Can anyone help me with an alternative or tell me where i went wrong?
jOOQ is a very type safe API, so you cannot compare UUID types with String types using eq(), because the eq() method uses the generic <T> type of your CORRESPONDENCE.USERID column, which is UUID:
TableField<..., java.util.UUID> USERID = ...
Generating a UUID bind value in the Java client
You either have to supply an externalId in the form of a UUID type, e.g.:
CORRESPONDENCE.USERID.eq(UUID.fromString(externalId))
... or, you let jOOQ convert that type for you:
CORRESPONDENCE.USERID.eq(CORRESPONDENCE.USERID.getDataType().convert(externalId))
Both of the above are equivalent.
Generating a UUID bind value in the database
You can always also defer the type conversion work to the database by casting (which will result in a CAST(? AS UUID) being rendered:
CORRESPONDENCE.USERID.eq(DSL.cast(externalId, UUID.class));
... or by coercing the variable to adhere to the UUID type (trusting that the database can implicitly convert the VARCHAR type to a UUID type):
CORRESPONDENCE.USERID.eq(DSL.coerce(DSL.val(externalId), UUID.class));