JPA Error compiling query when using Oracle objects within a query - jpa

The following JPA query doesn't compile -
SELECT a FROM CUSTOMER a WHERE a.activeCustomer = 'N' AND a.customerInfo.city IN :cityName ORDER BY a.customerId
where the table CUSTOMER in Oracle database has a base type - CUSTOMERINFO which in turn has various values such as -
city
country
This base type CUSTOMERINFO is extended by LOCALBUSINESSCUSTOMERINFO and MNCBUSINESSCUSTOMERINFO and a few others.
I think this may be due to the fact that when I define the column in my entity I define it as follows -
#Entity
#Table(name = "CUSTOMER", schema = "DBA")
#Converter(name="CustomerInfoConvertor", converterClass=CustomerInfoConvertor.class)
public class Customer implements Serializable {
#Basic
#Convert("CustomerInfoConvertor")
#Column(columnDefinition = "CUSTOMERINFO")
private ICustomerInfo customerInfo;
}
I have tried this query using SQL and it works fine but using it from JPA (JPQL) throws compilation error.
Thanks for your help!

You have mapped your customerInfo as a basic, so it is a basic in JPQL.
The column is of an Object object type?
In EclipseLink 2.3 you can map this as an Embeddable and the #Struct annotation, and use an Embedded mapping from the Customer. Does the customer table have other columns or is it a type table? If it is a type table, then use the #Struct to map it.

Related

PostgreSQL function used in QueryDSL is not working, returns ERROR: syntax error at or near "."

This is my very first question on stackoverflow, so sorry in advance if anything is not as precise as it should be
In my project, I use Hibernate (as ORM framework) with QueryDSL lib, PostgreSQL as a database.
Basically, I need to check the size of a list 'arr', which is a property of some 'X' class, so I googled and found a way to use postgres functions with querydsl as follows (before you ask, I can't use native queries by the requirements):
BooleanBuilder builder = new BooleanBuilder();
builder.and(Expressions.booleanTemplate("function('array_length', {0})", qX.arr)
.castToNum(Integer.class).gt(0));
Everything compiles fine, but when the repository method is being called, I get an error:
ERROR: syntax error at or near "." Position: ...
I checked everything, but there are no "." in that position and near positions as well.
However, after setting spring.jpa.show-sql=true I found out that there is indeed a "." symbol somewhere in that position, and the result SQL statement looks like this:
... and cast(array_length(.) as int4)>?
which means, that JPA can't put my 'arr' inside the array_length() function (is that so?)
Why does this happen? Am I doing something wrong?
Thank you in advance
My entity class looks like that:
#EqualsAndHashCode(callSuper = true)
#Entity
#Table
#Data
#NoArgsConstructor
#TypeDefs({
#TypeDef(name = "list-array", typeClass = ListArrayType.class)
})
public class X extends BaseClass {
// private fields
#Type(type = "list-array")
#Column(name = "arr", columnDefinition = "bigint[]")
#ElementCollection
#OrderColumn
private List<Long> arr;
}
I tried without #ElementCollection and #OrderColumn annotations but that gives me cast errors
#ElementCollection and #OrderColumn are causing a first problem here. After they are removed (and the schema is setup correctly), the function call (SQL template) needs to be corrected.
The problem with #ElementCollection and #OrderColumn is that they represent an alternative approach for storing lists/arrays as part of an entity.
#ElementCollection stores the elements in a separate table, with each element in a separate row (each referencing the entity). To "remember" the correct order, an #OrderColumn is needed as part of the separate table, since rows are returned in arbitrary order if no order is specified (https://stackoverflow.com/a/20050403).
In contrast, ListArrayType and #Column(columnDefinition = "bigint[]") will enable saving the sequence of elements in one column of an entity row. Therefore, no separate table is used, and since the elements are not saved in separate rows, no additional order information is needed.
So without #ElementCollection and #OrderColumn the list mapping is already correctly setup. Be aware that your schema might currently be in a bad state, and you need to make sure that there is a bigint[] column in the entity table (can e.g. be auto-created by hibernate when #ElementCollection and #OrderColumn are removed).
2. Fixing the PostgresQL function call: array_length needs a second argument indicating the dimension of the array along which the length is returned (https://www.postgresql.org/docs/current/functions-array.html). So specifying the template string as follows should get you the correct result:
"function('array_length', {0}, 1)"
("1" being the requested array dimension).

Spring data jpa querydsl projection with joins

I'd like to optimize a queryDSL + Spring data query. Currently I am using a BooleanBuilder as the predicate, which would be fine, but it joins too many tables. I don't need all the columns from the tables and I don't need some of the tables at all. I believe using a projection would reduce the number of tables joined.
I tried with using a Projections.bean() and also with extending MappingProjection, but both approaches result in not using joins but selecting from multiple tables which results in less rows than what's needed.
My data structure consists of a Booking entity and some related entites like User, so looks something like the following:
#Entity
public class Booking {
#ManyToOne
#JoinColumn(name = "userId", nullable = false)
private User endUser;
}
#Entity
public class User {
#OneToMany(cascade = CascadeType.ALL, mappedBy = "endUser", fetch = FetchType.LAZY)
private List<Booking> bookings;
}
I implemented a custom queryDSL projection repository as described here: Spring Data JPA and Querydsl to fetch subset of columns using bean/constructor projection
I'm trying a projection like the following:
Projections.bean(Booking.class,
booking.uuid,
Projections.bean(User.class,
booking.endUser.uuid
).as(booking.endUser.getMetadata().getName()
);
The sql generated by the current solution looks something like this:
select (...)
from booking booking0_,
user user12_
where booking0_.user_id=user12_.id
So, how can I make QueryDSL join the tables instead of selecting from all of them?
Am I on the right path to try to optimize the query? Does the projection make sense?
I ended up creating a DB view, making an Entity for it and then querying that with querydsl. This is really simple, straightforward and the performance is good too.
This is probably where ORMs are just not capable enough.

Map two fields to one database column

Question: Am I somehow able to map two fields of my Entity class to only one Column in the Database?
Scenario: The database is not fully normalized. There exists one Column which contains a composite information. It is not my actual use case, but an comprehensible example might be X- and Y-coordinate of a point in the plane. So the Database may contain a String 12:45 and the Entity class should contain only two integer field x width value 12 and ywith value 45.
Currently the Entity class has just two additional getter and setter for x and y and performs the proper translation. But I am wondering if there is a way to let JPA do this for me magically in the background.
I am already working with custom converter classes, e.g. for a proper mapping between between enums and database columns, but this works only for a "one-to-one" mapping between the field in the Entity class and the column in the database.
Of course it would be the most preferable way to redesign the table in the database, but that's not an option at the moment.
Vendor specific solutions are also fine.
2 Entity fields into one database column can be done fairly simply by specifying JPA use your accessor in the entity to handle the conversion:
#Entity
#Access(AccessType.FIELD)
class myEntity {
#Id
int id;
#Transient
String x;
#Transient
String y;
#Mutable //EclipseLink specific to prevent change tracking issues
#Access(AccessType.PROPERTY)
#Column(name="yourDatabaseFieldName")
private String getCoords() {
return x+":"+y;
}
private void setCoords(String coords) {
//parse the string and set x+y.
}
EclipseLink and Hibernate have transformation mappings that are able to handle the reverse; 2 or more database fields into one java property but this is outside of JPA.

Selecting native collections defined with #ElementCollection from Entities in JPA

Let's suppose we have an Entity of this type:
#Entity
#Table(name="User")
public class User {
#Id
long id;
#ElementCollection
List<String> phones;
}
My goal is to have the complete list of phones, for all users, something like: "SELECT x.phones FROM User x"
I tried to build a Spring Data JPA query of this kind:
#Query("SELECT x.phones FROM User x")
List<String> findAllPhones();
But I get this exception:
org.hibernate.QueryException: not an entity
at org.hibernate.hql.internal.ast.tree.FromElementType.renderIdentifierSelect(FromElementType.java:188)
I had to resort to a native sql query to solve the problem.
Otherwise I have to wrap the phone number inside a new Entity, but I exactly want to avoid that.
Is there any way to solve this kind of problem using plain JPA or (even better) only Spring Data JPA methods?

How to retrieve nested data in JPQL?

working with OpenJPA2 persistence. I have a very simple entity class, that does have a String property and a List property. I do persist its instances flawlessly with the nested List (in a JSF2 web project). I check the database and there appears two tables (I use automatic schema generation), one for the entity itself, and other table for the nested List. All data persisted using EntityManager is stored fine on both tables.
Problem is I cannot retrieve nested data. I mean, I do a Query for getting all instances of the entity, but the List of all instances come empty.
(DB Engine is MySQL. ORM is OpenJPA2. Server is TomEE 1.6. IDE is Netbeans 8. I use automatic schema generation, so I DO NOT WANT to design the database tables, and I DO WANT to let the ORM create the tables, so I can work purely with objects and forget about DB.)
following is Entity Class code:
#Entity
public class Cliente implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String nombre;
#ElementCollection
private List<String> emails = new ArrayList<String>();
// getters and setters omitted for brevity.
It does have an associated Facade Class, which is ClienteFacade. It includes the getAll method which uses a JPQL Query.
public List<Cliente> listaClientes(){
Query query = em.createQuery("SELECT c FROM Cliente c");
return query.getResultList(); }
Problem is, I get all instances of the entity in a List, but all lists of List emails come out empty. I think problem may be in the JPQL query. Still trying to learn JPQL with some difficulty... so please, How can I retrieve the nested data with JPQL?
Many thanks!
Try #ElementCollection(fetch = FetchType.EAGER) because the default type is lazy. That means that the lists are not loaded directly.