PSQLException: ERROR: column "classification" is of type classification but expression is of type character varying - postgresql

I have the following JPA repo with insert query method:
public interface CMRepository extends JpaRepository <CMark, String> {
#Transactional
#Modifying
#Query(value = "INSERT INTO c_mark(class_fk, s_con_fk, dis_con_fk, rto_fk, version, classification) " +
"values(:class_fk, :s_con_fk, :dis_con_fk, :rto_fk, :version, :classification)", nativeQuery = true)
int insertCMark(#Param("class_fk") String class_fk, #Param("s_con_fk") String s_con_fk, #Param("dis_con_fk") String dis_con_fk,
#Param("rto_fk") String rto_fk, #Param("version") int version, #Param("classification") String classification);
}
When executed, I get the following error:
PSQLException: ERROR: column "classification" is of type classification but expression is of type character varying
The database has that field defined as USER-DEFINED. I believe from similar posts I am supposed to cast the classification field? If so, I am not sure how to do it. Thanks for any help!

ok, figured this out. I had to cast like this:
public interface CMRepository extends JpaRepository <CMark, String> {
#Transactional
#Modifying
#Query(value = "INSERT INTO c_mark(class_fk, s_con_fk, dis_con_fk, rto_fk, version, classification) " +
"values(:class_fk, :s_con_fk, :dis_con_fk, :rto_fk, :version, :classification\\:\\:classification)", nativeQuery = true)
int insertCMark(#Param("class_fk") String class_fk, #Param("s_con_fk") String s_con_fk, #Param("dis_con_fk") String dis_con_fk,
#Param("rto_fk") String rto_fk, #Param("version") int version, #Param("classification") String classification);
}
(notice the required escapes)

Related

EclipseLink + PostgreSQL: UUID stopped to work after the upgrade to 4.0.0

I'm using the UUID as a primary key in my solution and it worked perfectly on the older EclipseLink version 2.7.3, however, when I tried to upgrade to 4.0.0 I started getting an error during the invocation of the find method.
PK is defined as:
#Id
#Column(name="ID", columnDefinition="UUID")
#Convert(converter = UuidConverter.class)
protected UUID id;
Converter:
#Converter(autoApply = true)
public class UuidConverter implements AttributeConverter<UUID, UUID> {
#Override
public UUID convertToDatabaseColumn(UUID attribute) {
return attribute;
}
#Override
public UUID convertToEntityAttribute(UUID dbData) {
return dbData;
}
}
PostgreSQL trick to bypass the cast issue (please see https://www.eclipse.org/forums/index.php/t/1073632/
for the details):
create or replace function uuid(_text character varying) returns uuid language sql as 'select uuid_in(_text::cstring)';
create cast (character varying as uuid) with function uuid(character varying) as assignment;
Find method:
public T find(Object id) {
return getEntityManager().find(entityClass, id);
}
Error:
Internal Exception: org.postgresql.util.PSQLException: ERROR: operator does not exist: uuid = character varying
Hint: No operator matches the given name and argument types. You might need to add explicit type casts.
Position: 96
So, the cast issue has returned despite that both the function and the cast were defined as listed above.
Entities are being stored in the DB fine, the problem appears only when I try to fetch them.

JPQL Query - No constructor taking error?

I have a Card entity class with many columns.
I used dto because I want to get some columns from this Entity.
I created a DTO class and wrote a query to CardRepositoryCustom.
But when I try to run the Query I get various errors "No constructor taking".
My dto class:
#Data
#NoArgsConstructor
#AllArgsConstructor
public class CardDTO {
private String test1;
private String test2;
private String test3;
private String test4;
}
JPQL RepositoryCustom :
#Repository
#Transactional
public class CardRepositoryCustom {
public CardDTO test1() {
JpaResultMapper jpaResultMapper = new JpaResultMapper();
String q = "SELECT "+
" c.test1 "+
"FROM "+
" CardEntity c ";
Query query = entityManager.createQuery(q);
try {
return jpaResultMapper.uniqueResult(query, CardDTO.class);
} catch (NoResultException nre) {
return null;
}
}
}
Errors:
java.lang.RuntimeException: No constructor taking: java.lang.String
at org.qlrm.mapper.JpaResultMapper.findConstructor(JpaResultMapper.java:107) ~[qlrm-1.7.1.jar:na]
at org.qlrm.mapper.JpaResultMapper.uniqueResult(JpaResultMapper.java:64) ~[qlrm-1.7.1.jar:na]
at ....
I know how to fix this error.
You just need to write the following constructor in the DTO class as shown below.
public CardDTO(String test1) {
this.setTest1(test1);
}
Here I am curious, if I want test2, test3, test4 and write Query in Custom class, should there be as many constructors in DTO class as that number?
I think this method is really inefficient. Is there any solution I am not aware of?
This seems to be more about QLRM than JPA or Spring.
Judging from the error message the constructor has to match the arguments provided. Probably the easiest variant is to always provide all arguments, possibly with a value of null or some other literal.
The query in your example would then become.
SELECT c.test1, null, null, null FROM CardEntity c
Of course QLRM just provides a JpaResultMapper and it would probably not too difficult to provide your own, or offer a PR to QLRM that inspects names of the result set and tries to match them to parameter names or the constructor.

JPA Repository findByEnum does not cast the Argument Enum to String or Postgres Cast not working as expected

I have a Spring Boot (2.5.4) backend pointing to a Postgres (9.6) database. I have an entity in Spring that makes use of the #Enumerated(EnumType.String) annotation on a field of an Enum type. Persisting this entity works as expected and converts the Enum into a String. In Postgres, I have the respective enum casted to character varying. Things are working to this point except invoking a custom findBy "Enum" method in the JPA Repository interface. Now in Spring and Postgres I have defined the following:
Enum:
public enum EnumExampleType {
TYPE1, TYPE2
}
Entity:
#Entity
#Table(name = "enumexampletable")
#Data
#NoArgsConstructor
public class EnumExampleTable {
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "enum_example_table_id", columnDefinition="serial primary key")
private int enumExampleTableId;
#Column(unique = true, name="enum_example_type")
#Enumerated(EnumType.STRING)
public EnumExampleType enumExampleType;
}
Repo:
public interface EnumExampleTableRepo extends JpaRepository<EnumExampleTable, Integer> {
EnumExampleTable findByEnumExampleType(EnumExampleType enumExampleType);
}
Working Code as Expected
EnumExampleTable ex1 = new EnumExampleTable();
EnumExampleTable ex2 = new EnumExampleTable();
ex1.setEnumExampleType(EnumExampleType.TYPE1);
ex2.setEnumExampleType(EnumExampleType.TYPE2);
enumExampleTableRepo.save(ex1);
enumExampleTableRepo.save(ex2);
RestController: (to invoke) (not working)
#Autowired
EnumExampleTableRepo enumExampleTableRepo;
#GetMapping("/findByTest")
public EnumExampleTable enumTest() {
return enumExampleTableRepo.findByEnumExampleType(EnumExampleType.TYPE1);
}
When calling this code the following error is received:
Blockquote org.postgresql.util.PSQLException: ERROR: operator does not exist: enumexampletype = character varying
Hint: No operator matches the given name and argument type(s). You might need to add explicit type casts.
Postgres Database:
drop table if exists enumexampletable;
drop type if exists enumexampletype cascade;
drop cast if exists (character varying as enumexampletype);
create type enumexampletype as enum('TYPE1', 'TYPE2');
CREATE CAST (character varying as enumexampletype) with inout as implicit;
create table enumexampletable (
enum_example_table_id serial primary key,
enum_example_type enumexampletype
);
This suggests to me that either:
A: The findByEnumExampleType method does not convert the enum to a string
B: Postgres does not invoke this cast in this particular call
Also to Note: (A hard coded native query will function properly, but this is not the dynamic functionality I need)
#Query(value="select * from enumexampletable e where e.emum_example_type = 'TYPE1'", nativeQuery=true)
EnumExampleTable testNQ();
Thoughts or suggestions?

JPA eclipselink sum of integer in JPQL are not integers?

I'm using Eclipselink with postrgresql.
My entity is
public class PedaneMovimenti extends EntityBaseGest implements Serializable {
private static final long serialVersionUID = 1L;
...
#Column(name = "importo", nullable = false)
private Integer importo = 0;
...
In my JPQL Named query I sum the column importo, then use this value in a costructor of a class.
I have two constructor for the class used as projection:
public SaldoPedaneCliente(AnagraficaPGF anagrafica, TipoBancale tipo, Integer saldo);
public SaldoPedaneCliente(AnagraficaPGF anagrafica, TipoBancale tipo, Long saldo);
The JPQL query is
SELECT new com.path.SaldoPedaneCliente(
mov.mastro.anagrafica,
mov.tipobancale,
(
COALESCE(
SELECT SUM(m.importo)
FROM PedaneMovimenti m
WHERE m.mastro.anagrafica = mov.mastro.anagrafica AND m.tipobancale = mov.tipobancale
AND m.verso = com.bsssrl.bssstdgest.enums.VersoMovimento.IN
, 0)
))
from PedaneMovimenti mov WHERE mov.mastro.anagrafica IS NOT NULL
GROUP BY mov.mastro.anagrafica, mov.tipobancale
The query is ok, it works.
I've a type mismatch in the costructor:
javax.persistence.PersistenceException: java.lang.IllegalArgumentException: argument type mismatch
If I change the subquery with a constant (1 for example), it works fine, but if I use the sum, I've the exception.
So, does the sum on Integers is not an Integers or a Long?
EDIT: I've tryed also SELECT SUM(1) but I've the same error.
The sum of "Integer"s is a "Long" !
I've changed the order of the constructors: first the Long version, then the Integer version and it works.

Error while casting in JPQL

This is on a JSF + JPA web application.
When I used the following JPQL query which include casting, it gives an error difficult to understand.
This is the query
jpql = "select new data.dataStructure.PharmacyStockRow(amp.vmp.name, sum(s.stock), "
+ "sum(s.itemBatch.purcahseRate * s.stock), sum(s.itemBatch.retailsaleRate * s.stock))"
+ "from Stock s join treat(s.itemBatch.item as Amp)amp "
+ "where s.stock>:z and s.department=:d "
+ "group by amp.vmp ";
m.put("d", department);
m.put("z", 0.0);
This is the class created just to receive the result from the query.
package data.dataStructure;
public class PharmacyStockRow {
String code;
String name;
Double qty;
Double purchaseValue;
Double saleValue;
public PharmacyStockRow() {
}
public PharmacyStockRow(String name, Double qty, Double purchaseValue, Double saleValue) {
this.name = name;
this.qty = qty;
this.purchaseValue = purchaseValue;
this.saleValue = saleValue;
}
I have a Stock class which stores data about stocks. It has a ItemBatch class which represent a batch. Batch has an Item. That item is actually a Amp, which extends Item. Amp has a Vmp. I want to get the stocks by Vmp. It would have been very easy if ItemBatch has a property of Amp, but I had to use more generic Item as the reference. So I need to cast Item to Amp within the Java Resistance Query. I tried it but it gives following error.
I use EclipseLink 2.5 as the Persistance Provider.
Caused by: Exception [EclipseLink-6034] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.QueryException
Exception Description: Invalid query item expression [
Query Key vmp
Query Key item (entity.pharmacy.Amp)
Query Key itemBatch
Base entity.pharmacy.Stock].
Query: ReportQuery(referenceClass=Stock jpql="select new data.dataStructure.PharmacyStockRow(amp.vmp.name, sum(s.stock), sum(s.itemBatch.purcahseRate * s.stock), sum(s.itemBatch.retailsaleRate * s.stock)) from Stock s join treat(s.itemBatch.item as Amp)amp where s.stock>:z and s.department=:d group by amp ")
at org.eclipse.persistence.exceptions.QueryException.invalidExpressionForQueryItem(QueryException.java:622)
at org.eclipse.persistence.queries.ObjectLevelReadQuery.getLeafDescriptorFor(ObjectLevelReadQuery.java:1460)
at org.eclipse.persistence.queries.ObjectLevelReadQuery.getLeafMappingFor(ObjectLevelReadQuery.java:1408)
at org.eclipse.persistence.internal.queries.ReportItem.initialize(ReportItem.java:124)
at org.eclipse.persistence.queries.ConstructorReportItem.initialize(ConstructorReportItem.java:137)
at org.eclipse.persistence.queries.ReportQuery.prepare(ReportQuery.java:1044)
at org.eclipse.persistence.queries.DatabaseQuery.checkPrepare(DatabaseQuery.java:613)
at org.eclipse.persistence.queries.ObjectLevelReadQuery.checkPrepare(ObjectLevelReadQuery.java:823)
at org.eclipse.persistence.queries.DatabaseQuery.prepareCall(DatabaseQuery.java:1741)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.buildEJBQLDatabaseQuery(EJBQueryImpl.java:268)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.buildEJBQLDatabaseQuery(EJBQueryImpl.java:190)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.<init>(EJBQueryImpl.java:142)
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.<init>(EJBQueryImpl.java:126)
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.createQuery(EntityManagerImpl.java:1475)
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.createQuery(EntityManagerImpl.java:1497)
I failed to solved the issue, but did a work around. I add all the additional methods in the child class into the parent class so that the casting was not necessary.