JPA populate transient field with SQL query result column - java

I'm working with this native SQL request :
SELECT o.*, COUNT(*) OVER() AS total_count
FROM observation o
WHERE ...
ORDER BY code
LIMIT 1000;
I need to put the total_count information in a transient field in this object :
#Entity
#Table(name = "observation")
public class Observation {
#Column(name = "code")
private String code;
...other fields
#Transient
private Long totalCount;
}
in order to get List<Observation> results = query.getResultList(); with the totalCount information.
I know that #SqlResultSetMapping could do the job with #ConstructorResult, but the class has a lot of fields and I prefer avoid creating the constructor with all fields.
Is there an easier way to achieve this ?

Related

QueryDSL query failing when querying with entity with null ID

I have a DB with 40 columns, and a REST API in Spring Boot that can be used to query the DB with any combination of parameters, which necessitates the use of dynamic query creation, which is why I have chosen to use QueryDSL.
Before making the query, I convert the query params to the Entity object using an ObjectMapper, then do a count using something like:
queryFactory.select(qTableRequest.rowId.count()).from(qTableRequest).where(qTableRequest.eq(TableRequest))
which works fine when the #Id column of the Entity is not null, but fails with
TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing
when it's null.
Side note: I can't use Spring's Query by Example because there are cases where I need non-singular matching.
I tried to extract the non-null fields of the entity and construct the query using .and(), .or() etc. as a BooleanExpression and it works, but it requires a lot of boilerplate code and it would be nice to have a simple solution to query for the Entity directly.
My question is: is it possible to use an Entity in the query without an Id?
Entity:
#Entity
#Table(name = "table", schema = "schema")
#AllArgsConstructor
#NoArgsConstructor
#Getter
public class TableRequest {
#Id
#Column(name = "row_id")
public String rowId;
#Column(name = "order_id")
public String orderId;
... // 38 more rows
}
Query:
private BooleanExpression constructQuery(SearchRequest searchRequest) {
TableRequest searchRequestToEntity = objectMapper.convertValue(SearchRequest, TableRequest.class);
BooleanExpression queryParameters = qTableRequest.eq(searchRequestToEntity);
...
}
public SearchResponse search(SearchRequest searchRequest) {
BooleanExpression queryParameters = constructQuery(searchRequest);
long rowCount = queryFactory.select(qTableRequest.rowId.count())
.from(qTableRequest).where(queryParameters).fetchFirst();
...
}

How to check if an entity exists in DB using methods from SimpleJpaRepository

I am trying to find out if any entity exists matching a few conditions using methods available in SimpleJpaRepository.
My entity looks like this:
#Entity
public class MyEntity{
#Id
private int id;
#ManyToOne
private TaskEntity taskEntity;
#Column
private String name;
...
And my method looks like this:
/** Check if any entity exists with the given taskId and name */
public boolean existsByTaskAndName(int taskId, String name){
MyEntity probe = new MyEntity();
probe.setTask(entityManager.getReference(TaskEntity.class, taskId));
probe.setName(name);
return exists(Example.of(probe, ExampleMatcher.matching().withIgnoreCase()));
}
I was expecting the sql query to look something like this:
select top 1 * from my_entity where task=#taskId and lower(name)=lower(#name)
But in reality, the SQL query contained inner joins with TaskEntity and all entities related to TaskEntity, and the where clauses contained comparison between all fields from TaskEntity and all fields from all other related entities. (in total 10+ inner joins and 100+ where clauses).
How can I write the method so that it only compares the columns "task" and "name", without any joins and without reading unnecessary objects?
I would do a JPQL Query like this:
select case when (count(*) > 0) then true else false end from MyEntity m where m.taskEntity.id = :id and upper(m.name) = upper(:name)
It would return you a nice boolean.

How to get the required fields data from an Entity to VO object using Spring Data MongoDB

In Spring Data Jpa we have a flexibility to map the required fields query result to a VO object with out exposing the entity object outside.
DB Used :: mysql
1st way ::
#Query("SELECT new CountryVO(c.id,c.name) FROM Country c")
public List<CountryVO> getCountries();
//Country Entity
public class Country{
private long id;
private String name;
#DBRef
private State state;
}
// State Entity
public class State{
private long id;
private String name;
}
//Country VO
public class CountryVO{
private long id;
private String name;
private String stateName;
}
2nd way ::
#Query("SELECT DISTINCT c.name FROM Country c")
public List<String> getNames();
Now my point is I am using Spring Data mongoDB with mongoDB database and here the querying way is different like below
#Query(value = "{}", fields = "{'id':1,'name':1,'state.name':1}")
List<CountryVO> getAllCountries();
In the above query we can mention what ever fields we want in the fields attribute and the remaining fields will come as null values, but I want to map the output result to a VO like Spring Data Jpa.
Please let me know any possibilities
Thanks in Advance
Just use your CountyVO as return type:
#Query(value = "{}", fields = "{'id':1,'name':1}")
List<CountryVO> getAllCountries();

Define a variable in Entity class which is not a column

In my WAS application, I have a requirement to define a variable(String) in an Entity class that maps to a table.
So the fields that are related to the table have annotation as #Column(name="column_name")
I have a requirement to add a new field/variable to this Entity class that is not a column in table. If I declare it as a normal field, JPA converts this field also in the SQLs. This is causing SQL -206 error(as expected).
How to do I declare this field? Is there an annotation that I can use to say its a custom variable and not related to any of the columns in the table defined by this Entity?
example:
#Entity
#Table(name = "TABLE_1")
#NamedQueries(
{
#NamedQuery(name = "abc:findTableContent", query = "SELECT u FROM TABLE_1 u WHERE u.Id = :iD"),
})
public class TableEntity1 implements Serializable
{
#Id
#Column(name = "TABLE1_ID")
private Long iD;
#Column(name = "DESC")
private String desc;
private String error;
}
So if I run the namedquery, it gets executed as "SELECT t0.iD, t0.desc, t0.error FROM TABLE_1 u WHERE u.iD=?"
How do I solve this? Thanks for your help!
I found the answer. I could mark the field or variable as #javax.persistence.Transient

Hibernate Annotations with SQL query

I want to create a hibernate SQL query and cast it to an object without creating the table.
for example i have
StringBuilder query = new StringBuilder();
query.append("SELECT groupId, categoryId, name FROM AssetCategory");
SQLQuery sqlQuery = session.createSQLQuery(query.toString());
sqlQuery.addEntity("Categories", Categories.class);
List<Categories> list = sqlQuery.list();
The category object is declared like this :
#Entity
public class Categories implements Serializable {
#Column(name = "name")
String name;
#Column(name = "categoryId")
Long categoryId;
#Column(name = "groupId")
Long groupId;
Of course this cant work because there is no ID. And this table does not need to be created either. So how would i go about declaring this ?
Any hints ?
I just cant find the documentation.
you can use a SQLTransformer to do this.. you wont need the annotations in the pojo even.
read this. it will help you realize what you should be doing.

Categories