Java Enums with different number of parameters - java

I want to create an enum that represents various JPA NamedQueries. Each query though may have a different number/type of parameters. So I when I want to refer to the query / query placeholder I can do something like the following:
Entity.Queries.FIND_PERSON_BY_NAME_AND_ADDRESS.toString(); //gets the Query itself
Entity.Queries.Query1.FIND_PERSON_BY_NAME_AND_ADDRESS.PLACEHOLDER_NAME ; //gets the string of the placeholder "name"
Entity.Queries.Query1.FIND_PERSON_BY_NAME_AND_ADDRESS.PLACEHOLDER_ADDRESS; //gets the String of the placeholder "address"
I want to do this so when I create the named queries I can do the following
Query q = entitiManager.createNamedQuery(Entity.Queries.FIND_PERSON_BY_NAME_AND_ADDRESS.toString);
q.setParameter(Entity.Queries.Query1.FIND_PERSON_BY_NAME_AND_ADDRESS.PLACEHOLDER_ADDRESS, address);
Is this possible with enums, or should I just use final constants in private static classes or something?

Related

How to pass Dynamic value in #Where in JPA

I want to filter entity by using #Where and want to know how to pass dynamic value in JPA
Example : #Where(clause = "name = 'Alas'") //Here 'Alas' is static i want to make it dynamic
You cannot make the structure of the WHERE clause itself dynamic in this way. Assuming you want to make certain portions of the WHERE clause dynamic, you could use:
SELECT *
FROM yourTable
WHERE name = ? OR ? IS NULL;
To the ? placeholders above, you would bind 'Alas'. If you don't pass any value, then the crtierion on name would simply be ignored.

Spring JPA Criteria Builder specific columns

I'm using JPA criteria builder to query Database for the records. However, I want to return specific columns from a table using JPA criteria API.
Currently, my implementation returns full object. But, I want to return only specific columns and those columns could be dynamic. Below code will query on Person table and returns Full-Object of Person.
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Person> query = cb.createQuery(Person.class);
Root<Person> root = query.from(Person.class);
query.select(cb.equal(root.get("id"), 1));
TypedQuery<Person> result = em.createQuery(query);
List<Person> personList = result.getResultList();
I know we can create a minified class like PersonMini which will include only a specific field like below but, In my case, the columns could be dynamic and based on the user's preference.
class PersonMini {
private long id;
private String name;
// .. constructor and getter/setter
}
It's not feasible to create a separate mini-classes of Person. Has anyone solved such issue before or could you please suggest another approach if that would solve my problem.
EDIT:
As mentioned in here.
If the type of the criteria query is CriteriaQuery for some user-defined class X (i.e., a criteria query object created by passing a X class argument to the createQuery method), the elements of the list passed to the multiselect method will be passed to the X constructor and an instance of type X will be returned for each row.
If I use multiselect method and use PersonMini Class then I will need a constructor for each and every combination of the fields. Because the selection of the fields is done by Users. selection of fields is not static.
Suppose, in PersonMini class I have 3 fields. Id, Name, and City then User could choose Id and Name, Name and City, City(alone), Id(alone), Id and City. For each combination I need constructor otherwise it will throw error runtime.
For two-three field, it is feasible to have a different combination of constructor but for 15-20 field it is not.

Hibernate: Fetching columns with their aliases

Consider this trivial query:
SELECT 1 as first, 2 as second
When using Hibernate we can then do something like:
em.createNativeQuery(query).fetchResultList()
However, there seem to be no way of getting the aliases (or column names). This would be very helpful for creating List<Map<String, Object>> where each map would be a row with their aliases, for instance in this case: [{first: 1, second: 2}].
Is there a way to do something like that?
I would suggest a bit different approach which may meet your needs.
In JPA 2.1 there is a feature called "result set mapping".
Basically you have to define a POJO class which would hold the result values (all the values must be passed using the constructor):
public class ResultClass{
private String fieldOne;
private String fieldTwo;
public ResultClass(String fieldOne, String fieldTwo){
this.fieldOne = fieldOne;
this.fieldTwo = fieldTwo;
}
}
Then you have to declare the mapping on one of your entities (does not matter on which, it just has to be a declated #Entity):
#SqlResultSetMapping(name="ResultMapping", classes = {
#ConstructorResult(targetClass = ResultClass.class,
columns = {#ColumnResult(name="columnOne"), #ColumnResult(name="columnTwo")})
})
The columnOne and columnTwo are aliases as declared in the select clause of the native query.
And finally use in the query creation:
List<ResultClass> results = em.createNativeQuery(query, "ResultMapping").getResultList();
In my opinion this is more elegant and "a level above" solution as you are not working with a generic Map key/values pairs but with a concrete POJO class.
You can use ResultTransformer interface . Implement custom mapper for mapping values with aliases.
here is example https://vladmihalcea.com/why-you-should-use-the-hibernate-resulttransformer-to-customize-result-set-mappings/
with ResultTransformer you can easy customize result set type , especially if you need aliases

JOOQ multi-field custom type converter

We have some custom types that reflected to multiple db fields. For example
PersonName{
String salutation,
String firstName,
String lastName
}
stored as 3 separate db fields.
And it's boring to always write
db.select(PERSON.FIRST_NAME, PERSON.LAST_NAME, PERSON.SALUTATION, ... some other fields)
then fetch the record and create PersonName type from the appropriate record fields.
The idea is to define some multi-column custom field PERSON_NAME, which will be expanded by jooq into three "real" fields during the query execution, and packed to the one PersonName object in the result.
Looks like it's possible to do something like this with org.jooq.impl.AbstractField, but I'm wondering, may be there is a solution for such case already.
There are pending feature requests to support this kind of functionality:
https://github.com/jOOQ/jOOQ/issues/2360 (nested records)
https://github.com/jOOQ/jOOQ/issues/2530 (fetch groups)
With out-of-the-box functionality of jOOQ 3.6, you could store those columns somewhere as:
Field<?>[] personName = {
PERSON.SALUTATION,
PERSON.FIRST_NAME,
PERSON.LAST_NAME
};
And then select them as such:
db.select(personName)
.select(... some other fields);

Get physical column value with entity property value using hibernate

I have a table T with columns defined as usual.
#Entity
#Table(name="T")
public class T {
#Column(name="test_id")
private Long testId;
}
Given entity property "testId", I want to get corresponding DB column name (i.e. "test_id"). How could it be achieved?
Edit 1:
I want to keep this column at separate location with actual DB column name (test_id) than testId. I fetched these values from DB using HQL which have key as entity name (i.e. testId) and I want actual column name in DB.
If I understood your requirement correctly, you want to use HQL while having a consistent name for both DB column and the entity field, like this:
SELECT t.test_id FROM Test t
instead of
SELECT t.testId FROM Test t
There is only one way to do that - renaming the field to test_id. HQL works on entities, not on DB tables, so you must use proper field names in the query.
Since test_id contradicts the usual Java coding conventions, I would advise against it.
EDIT: Getting the annotation attribute value with reflection would work along this outline:
Field field = MyEntity.class.getDeclaredField("testId");
Column a = field.getAnnotation(Column.class);
String columnName = a.name();
I would try to avoid this by any means, but if you're really sure you'll need it, use:
Configuration configuration = sessionFactory.getConfiguration();
PersistentClass persistentClass = configuration
.getClassMapping(T.class.getName());
String columnName = ((Column) persistentClass.getProperty("testId")
.getColumnIterator().next()).getName();
See also Get table column names in Hibernate

Categories