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
Related
I would like manipulate a jOOQ DSL query changing its SELECT columns and WHERE conditions.
For example:
DSLContext ctx = ...;
SelectHavingStep query = ctx.select(MyEntity.MY_ENTITY.ZIP, DSL.count(MyEntity.MY_ENTITY.ZIP))
.from(MyEntity.MY_ENTITY)
.where(MyEntity.MY_ENTITY.ID.gt("P"))
.groupBy(MyEntity.MY_ENTITY.ZIP);
Use case 1:
I would like to pass the above query to a utility class that will produce the same query just with with a different SELECT, for example:
ctx.select(DSL.count())
.from(MyEntity.MY_ENTITY)
.where(MyEntity.MY_ENTITY.ID.gt("P"))
.groupBy(MyEntity.MY_ENTITY.ZIP);
This particular example is to be able to create paginated results showing the total number of rows of the query.
Use case 2:
I would like to pass the above query to a utility class that will produce the same query just with with a modified WHERE clause, for example:
SelectHavingStep query =
ctx.select(MyEntity.MY_ENTITY.ZIP, DSL.count(MyEntity.MY_ENTITY.ZIP))
.from(MyEntity.MY_ENTITY)
.where(
MyEntity.MY_ENTITY.ID.gt("P")
.and(MyEntity.MY_ENTITY.ZIP.in("100", "200", "300"))
)
.groupBy(MyEntity.MY_ENTITY.ZIP);
This particular example is to further restrict a query based on some criteria (i.e. data visibility based on the user doing the query).
Is this possible?
Currently I'm using helper classes to do this at query construction time in the application code. I would like to move the responsibility to a library so it can be enforced transparently to the app.
Thanks.
You shouldn't try to alter jOOQ objects, instead you should try to create them dynamically in a functional way. There are different ways to achieve your use-cases, e.g.
Use case 1:
An approach to generic paginated querying can be seen here: https://blog.jooq.org/calculating-pagination-metadata-without-extra-roundtrips-in-sql/
Ideally, you would avoid the extra round trip for the COUNT(*) query and use a COUNT(*) OVER () window function. If that's not available in your SQL dialect, then you could do this, instead:
public ResultQuery<Record> mySelect(
boolean count,
Supplier<List<Field<?>>> select,
Function<? super SelectFromStep<Record>, ? extends ResultQuery<Record>> f
) {
return f.apply(count ? ctx.select(count()) : ctx.select(select.get()));
}
And then use it like this:
mySelect(false,
() -> List.of(MY_ENTITY.ZIP),
q -> q.from(MY_ENTITY)
.where(MY_ENTITY.ID.gt("P"))
.groupBy(MY_ENTITY.ZIP)
).fetch();
This is just one way to do it. There are many others, see the below link.
Use case 2:
Just take the above example one step further and extract the logic used to create the WHERE clause in yet another function, e.g.
public Condition myWhere(Function<? super Condition, ? extends Condition> f) {
return f.apply(MY_ENTITY.ID.gt("P"));
}
And now use it as follows:
mySelect(false,
() -> List.of(MY_ENTITY.ZIP),
q -> q.from(MY_ENTITY)
.where(myWhere(c -> c.and(MY_ENTITY.ZIP.in("100", "200", "300")))
.groupBy(MY_ENTITY.ZIP)
).fetch();
Again, there are many different ways to solve this, depending on what is the "common part", and what is the "user-defined part". You can also abstract over your MY_ENTITY table and pass around functions that produce the actual table.
More information
See also these resources:
https://www.jooq.org/doc/latest/manual/sql-building/dynamic-sql/
https://blog.jooq.org/a-functional-programming-approach-to-dynamic-sql-with-jooq/
I'm building REST API connected to ORACLE 11G DB. API sends data to Android client using JSON. To get data I'm using JpaRepository, and #Query annotations.
I want to provide data for charts: number of contracts in years.
I have native SQL query:
select aa.ROK, count(aa.NUMER_UMOWY)
from (select distinct NUMER_UMOWY, ROK from AGR_EFEKTY) aa
group by aa.ROK order by aa.ROK
Result of query using SQL Developer look like this:
I tried to get result using native query:
But result is always like this:
or error depending what I try.
Is it possible to obtain list of count() results using #Query?
If not, what should I use?
Thanks in advance :-)
I think What you are trying to use here is spring data projection.
As mentioned in the reference doc:
Spring Data query methods usually return one or multiple instances of
the aggregate root managed by the repository. However, it might
sometimes be desirable to create projections based on certain
attributes of those types. Spring Data allows modeling dedicated
return types, to more selectively retrieve partial views of the
managed aggregates.
and particularly closed projection where all accessor methods match the target attributes. In your case the count is not an attribute of your aggregate.
To perform what you want you can use constructor as follow :
class ContractsDto{
private String rok;
private int count;
public ContractsDto(String rok, int count) {
this.rok=rok;
this.count =count;
}
// getters
}
The query will be:
#Query(value = "select new ContractsDto(aa.rok , /*count */) from fromClause")
List<ContractsDto> getContractsPerYear();
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'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);
I'm trying to get a list of multiple columns from my table using QueryDSL, and automatically fill my DB object, like this example in an older manual:
List<CatDTO> catDTOs = query.from(cat)
.list(EConstructor.create(CatDTO.class, cat.id, cat.name));
The problem is that it looks like the EConstructor class was removed in version 2.2.0, and all the examples I find now are like this:
List<Object[]> rows = query.from(cat)
.list(cat.id, cat.name);
Which forces me to manually cast all the objects into my CatDTO class.
Is there any alternative to this? Any EConstructor alternative?
EConstructor has been replaced with ConstructorExpression in Querydsl 2.0. So your example would become
List<CatDTO> catDTOs = query.from(cat)
.list(ConstructorExpression.create(CatDTO.class, cat.id, cat.name));
You can also annotate the CatDTO constructor and query like this
List<CatDTO> catDTOs = query.from(cat)
.list(new QCatDTO(cat.id, cat.name));
Alternatively you can use the QTuple projection which provides a more generic access option
List<Tuple> rows = query.from(cat)
.list(new QTuple(cat.id, cat.name));
The actual values can be accessed via their path like this
tuple.get(cat.id)
and
tuple.get(cat.name)
Tuple projection will probably be used in Querydsl 3.0 for multiple columns projections instead of Object arrays.
using queryDSL 4 and Java 8 stream:
List<CatDTO> cats = new JPAQueryFactory(entityManager)
.select(cat.id, cat.name)
.from(cat)
.fetch()
.stream()
.map(c -> new CatDTO(c.get(cat.id), c.get(cat.name)))
.collect(Collectors.toList());
Another alternative is to use the class Projections. It will construct the object using the fields you pass as parameters, like the EConstructor. Example:
List<CatDTO> catDTOs = query.from(cat)
.list(Projections.bean(CatDTO.class, cat.id, cat.name));
Reference: http://www.querydsl.com/static/querydsl/4.0.5/apidocs/com/querydsl/core/types/Projections.html