getNamedQuery with explicit custom class - java

Say I have a Person model (Java class and Database table) which has columns/fields like name, age, gender, height, weight.
Now there are 2 possibilities
1) I would need the entire column data..so i would have the named query
as;
#NamedQuery(name = "Person.findAll", query = "Select p from Person
WHERE ..."
2) I need only specific column data..so i would have the named query as;
#NamedQuery(name = "Person.findSpecific", query = "Select p.name,
p.age from Person WHERE ..."
In the first case, if I call/execute the named query as;
Query query = getNamedQuery("Person.findAll");
it automatically maps the response to the Person Java class. But in the 2nd case (specific columns), it does not. It shows the response as Vector with Object array.
My question is is there any explicit way of making the query response map automatically to my custom class when I am using the specific column query
I have already tried
Query query = getNamedQuery("Person.findSpecific",Person.class);
But that again does not map it to Person class.

You can use constructor expressions in the select clause of any JPA query:
select new my.app.PersonView(p.name, p.age) from Person p ...
In this case, for every line in the result, a new PersonView instance is created.
Note that this instances are NOT connected to the data source (they are not managed), so you will not be able to change the underlying data by modifying the instances.
That's why I suggest to NOT use entity classes in constructor expressions to not mix them up with 'real' entities. Instead write custom 'transfer objects' that only carry the data. Either one tailored class per projection or - if many different projections on the same entity are required - one bigger class with multiple constructors that is used for all projections. In that case, some fields will always be empty.

Related

Is there a way to select all columns for a SELECT statement with JOINs without breaking the entity mapping?

I have a application_user table with a corresponding UserEntity record. Additionally, I have a user_meta_data table with a UserMetaDataEntity record as a 1:1 relation to the user.
#Table("application_user")
record UserEntity(#Id #Nullable Long id,
// more columns
#Nullable
UserMetaDataEntity metaData
) {
// (...)
}
Currently, I need to directly write SQL queries, as I have some complex queries at hand that can't be modeled easily via function names. In these queries, I need to explicitly select all columns
#Query("""
SELECT application_user.ID AS ID, user_meta_data.phoneNumber AS USERMETADATA_PHONE_NUMBER
FROM application_user
INNER JOIN user_meta_data ON user_meta_data.user_id = application_user.id
""")
Stream<UserEntity> streamUsersWithMetaData();
But I want to avoid explicitly defining column names, as my actual entities have many columns. I would prefer calling SELECT * FROM application_user INNER JOIN ... but this doesn't work, as Spring Data JDBC expects the column names to be prefixed with the joined table name.
Is there a way to define custom SQL queries without needing to define all columns in the SELECT statement?
You can't use SELECT * but there are at least two ways you can minimise the pain.
Either you define a static final String containing the list of columns and concatenate them with the rest of the query.
Alternatively you can specify a RowMapper doing the mapping. It could wrap the ResultSet and forward the call to the original EntityRowMapper

How to create jooq custom record?

How can I create a custom jOOQ Record from existing two others, i.e. merge properties from two existing Record Objects.
For example:
CustomerRecord(id, name, surname),
ProductRecord(id, customer_id, description)
SELECT * FROM Customer JOIN Product ON Customer.id = Product.customer_id;
After such a query I'll get RecordImpl object and I want to have custom one with access to field properties from both tables.
There are several options to achieve what you're looking for.
Use views
One of them would be to simply create a view:
-- Potentially disambiguate the ID (and other) columns
CREATE VIEW CustomerAndProducts AS
SELECT * FROM Customer JOIN Product ON Customer.id = Product.customer_id;
The code generator would then pick up that view and generate a CustomerAndProductsRecord for you
Use your own CustomRecord
You can create your own TableRecord subtype by extending org.jooq.impl.CustomRecord as is documented here:
https://www.jooq.org/doc/latest/manual/sql-building/queryparts/custom-queryparts
They work almost like ordinary TableRecord types and can have your own set of getters / setters
Use any class you like
You don't have to use records. jOOQ can fetch your results into any kind of class (which may happen to be records, see above) using the following code:
List<MyClass> list =
DSL.using(configuration)
.select()
.from(CUSTOMER)
.join(PRODUCT)
.on(CUSTOMER.ID.eq(PRODUCT.CUSTOMER_ID))
.fetchInto(MyClass.class);
In the above example, the DefaultRecordMapper is applied to map between jOOQ's records and your class. See its Javadoc for details.

Java Entity Object of Union Query

I am attempting to create a domain/entity class based on a complex query. The query unions a bunch of tables together and unfortunately I am not able to create a view on the database for this query. I have been trying to set up the entity object but I am unsure of how to ensure that the marshaling works properly (and ensure the entity acts as read-only object).
As an example of the query, I am doing something like this:
Select
U_T.a,
U_T.b,
U_T.c,
C_T.a
FROM
(select
A_T.a,
null as b,
A_T.c,
1 as ind
from A_T
UNION
select
B_T.a,
B_T.b,
null,
0 as ind
FROM B_T
) U_T
left outer join C_T on C_T.fk_a = U_T.a;
The other issues are that this union can result in instances where there is no unique key column. This is fine as this data is for viewing only, and never editing. However the #Entity annotation wants a column to be listed with the #ID annotation. Another issue is that I do not believe I can use the other entity classes as the goal is to reduce the number of DB transactions from this query (as the actual one can result in hundreds of recursive queries being performed).
If I need to give any more information please let me know.

JPA select rows with where clause

I know that entityManager.find() method can be used to fetch a row with the primary key.
But I have a requirement to define a common find method which accepts a map having the where clause conditions. In the map, key will be the column name and value will be the column name value of the where clause. This method should return the list of selected rows.
Can some one help me out?
Take a look at: EntityManager.createQuery. If I understand your question correctly, this will allow you to create the query that you would like to execute. You could also, take a look at using a CriteriaBuilder.
find fetches the row respect to the primary key.Now as you want
"common find method which accepts a map having the where clause conditions. In the map, key will be the column name and value will be the column name value of the where clause. This method should return the list of selected rows"
for this you have to go for CriteriaQuery like this :
The following simple Criteria query returns all instances of the Pet entity in the data source:
EntityManager em = ...;
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
cq.select(pet);
TypedQuery<Pet> q = em.createQuery(cq);
List<Pet> allPets = q.getResultList();
The equivalent JPQL query is:
SELECT p FROM Pet p
Moreover i will advise you to go for annotation based mapping in your entities & look for setter & getter for the methods.In that design also you can have customized method by java logic for this go here to read.
Following might be overkill, but is a fairly generic way to approach it utilizing the criteriaBuilder. While I can't paste the code here (work) I created an abstract BaseFilter<Entity> class.
The easy part is then having the implementing objects provide getXX, setXX properties. A getPredicates() was then added to return an ArrayList of predicates that the abstract BaseDAO could then invoke to perform the query.
We worked specifically with the getXX and setXXX so we could reference the elements via eg, get(Entity1_.childObject).get(ChildObject_.grandChildObject) to assist in refactoring. JPA also supports it via string name so you could implement the getPredicates with that.
JPA requires the actual Entity.class reference in their calls it was a bit of fun trying to obtain it. Eventually a google search turned it up.

Hibernate aggregates + Spring MVC

I am using Hibernate with my Spring MVC project.
Lets say my model has 2 objects each linked to Oracle tables, respectively USERS (USERID, NAME) and USERMONEYDATA (CATEGORY, USERID, AMOUNT)
My users can add , edit and remove rows in USERMONEYDATA, that belongs to them of course.
Now, I want to have a view that aggregates those data.
Using oracle, I made a simple view to get the total amount per user and category :
select userid, category, sum(amount)
from USERS a inner join USERMONEYDATA b on a.USERID = b.USERID
group by userid, category
But what is the best way to use it? should I create a new MODEL object specifically for this view ?
Should I aggregate directly in Hibernate ? But if yes, how do I display the results if I dont have a specific POJO object to map it to ?
thanks
If User and UserMoneyData are mapped as Hibernate entities, it's a natural choice to run aggregate queries in Hibernate.
By default, HQL or JPQL SELECT clause with multiple paths produces tuples in the form of Object[]. Since this kind of data is read-only, you may display these arrays directly, without converting them to objects.
Another option is to create a POJO for representing results of the query and use a constructor syntax SELECT NEW MoneyReport(u.userId, d.category, SUM(d.amount)) .... These POJOs don't need to be entities.
See also:
Chapter 15. HQL: The Hibernate Query Language

Categories