JPA CriteriaBuilder: Predicate with a Serializable field throws an exception - oracle

I have an entity with a persistent field declared as Serializable.
I would like to build a query with the CriteriaBuilder, that filters the results by the Serializable field.
The database is Oracle, and the field type is RAW(255) as hbm2ddl defined it.
If i write the query with a plain JPQL TypedQuery, everything works fine (the Serializable field is the one with the name "entityId"):
TypedQuery<Change> query = em.createQuery("FROM Change c WHERE c.entityClass = :class AND c.entityId = :id", Change.class);
query.setParameter("class", Person.class.getName());
query.setParameter("id", new Integer(2287));
query.getResultList();
However, the very same query with criteria builder does not work:
final CriteriaBuilder builder = em.getCriteriaBuilder();
final CriteriaQuery<Change> criteriaQuery = builder.createQuery(Change.class);
final Root<Change> from = criteriaQuery.from(Change.class);
final CriteriaQuery<Change> select = criteriaQuery.select(from);
final List<Predicate> predicates = new ArrayList<>();
predicates.add(builder.equal(from.get("entityClass"), Person.class.getName()));
predicates.add(builder.equal(from.get("entityId"), new Integer(2287)));
select.where(predicates.toArray(new Predicate[predicates.size()]));
final TypedQuery<Change> query = em.createQuery(select);
query.getResultList();
It throws the following exception after invoking getResultList():
[2013-05-21 16:12:45,960] [com.mycompany.myproduct.server.Main.startServer(Main.java:56)] [ERROR] [main] - Error starting Server: org.hibernate.exception.SQLGrammarException: could not extract ResultSet
javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not extract ResultSet
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1387)
...
Caused by: org.hibernate.exception.SQLGrammarException: could not extract ResultSet
...
Caused by: java.sql.SQLSyntaxErrorException: ORA-00932: inconsistent datatypes: expected BINARY got NUMBER
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:445)
...
Change.java:
#Entity
#Table(name = "T_REVISION_CHANGE")
#SequenceGenerator(name = "seq_revision_change", sequenceName = "SEQ_REVISION_CHANGE", allocationSize = 1)
public class Change {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_revision_change")
private Integer id;
#Column(name = "ENTITY_CLASS")
private String entityClass;
#Column(name = "ENTITY_ID")
private Serializable entityId;
}
I tried to manually serialize the Integer but the same kind of exception was thrown saying that a Serializable instance was expected instead of a byte array... :)
Any comment would be much appreciated.

Related

Duplicate or Null error when trying to send POST request for JSON Object with Foreign Key using Spring JPA

Here's my parent entity:
#Entity(name = "DrivingInstructor")
#Table(name = "driving_instructor")
#Getter
#Setter
#NoArgsConstructor
public class DrivingInstructor {
#Id
#Column(name = "driving_instructor_id")
private long drivingInstructorId;
#Column(name = "driving_instructor_name")
#Size(max = 128)
private String drivingInstructorName;
#Column(name = "specialization")
#Size(max = 200)
private String specialisation;
}
And here's my supposed child entity:
#Entity(name = "DrivingStudent")
#Table(name = "driving_student")
#Getter
#Setter
#NoArgsConstructor
public class DrivingStudent {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "driving_student_id")
private long drivingStudentId;
#Column(name = "driving_student_name")
#Size(max = 128)
private String drivingStudentName;
#ManyToOne(cascade = CascadeType.ALL, targetEntity = DrivingInstructor.class)
#JoinColumn(name = "driving_instructor_id", referencedColumnName = "driving_instructor_name", insertable = false, updatable = false)
private DrivingInstructor drivingInstructor;
}
Here's the relevant chunk of my service class for inserting/saving an instance of a DrivingStudent into the database:
#RequestMapping(path = "api/v0/driving-school")
#RestController
#AllArgsConstructor
public class DrivingStudentRestController {
private final DrivingStudentServiceImpl drivingStudentServiceImpl;
#PostMapping
Long insertOrUpdateDrivingStudent(#Valid #RequestBody DrivingStudent drivingStudent) {
return drivingStudentServiceImpl.insertOrUpdateDrivingStudent(drivingStudent);
}
}
DrivingStudentServiceImpl is just an abstraction layer for Repository class that extends JpaRepository<DrivingStudent, Long>, so insertOrUpdateDrivingStudent() is practically just using the save() method from CrudRepository.
An instance of DrivingInstructor is already pre-inserted with drivingInstructorId of 1, and so I tried to execute a POST request via Postman using this JSON object:
{
"drivingStudentName": "Peter Parker",
"drivingInstructor": {"drivingInstructorId": 1}
}
And I'm getting this exception:
2021-08-27 20:03:37.554 ERROR 16108 --- [nio-8080-exec-3] o.h.engine.jdbc.spi.SqlExceptionHelper :
ERROR: duplicate key value violates unique constraint "driving_instructor_pkey"
Detail: Key (driving_instructor_id)=(1) already exists.
2021-08-27 20:03:37.590 ERROR 16108 --- [nio-8080-exec-3] o.a.c.c.C.[.[.[/].[dispatcherServlet] :
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception
[Request processing failed; nested exception is
org.springframework.dao.DataIntegrityViolationException:
could not execute statement; SQL [n/a];
constraint [driving_instructor_pkey];
nested exception is org.hibernate.exception.ConstraintViolationException:
could not execute statement] with root cause
org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "driving_instructor_pkey"
Detail: Key (driving_instructor_id)=(1) already exists.
I also tried revising my RestController's PostMapping to look like this, but still nothing changes:
#RequestMapping(path = "api/v0/driving-school")
#RestController
#AllArgsConstructor
public class DrivingStudentRestController {
private final DrivingInstructorRepository drivingInstructorRepository;
private final DrivingStudentServiceImpl drivingStudentServiceImpl;
#PostMapping
Long insertOrUpdateDrivingStudent(#Valid #RequestBody DrivingStudent drivingStudent) {
Optional<DrivingInstructor> drivingInstructor = drivingInstructorRepository.findById(drivingStudent.getDrivingInstructor().getDrivingInstructorId());
if (drivingInstructor.isPresent()) {
drivingStudent.setDrivingInstructor(drivingInstructor.get());
return drivingStudentServiceImpl.insertOrDrivingStudent(drivingStudent);
}
return null;
}
}
The error I am getting then changed to:
2021-08-27 21:36:58.622 ERROR 11388 --- [nio-8080-exec-4] o.h.engine.jdbc.spi.SqlExceptionHelper :
ERROR: null value in column "driving_instructor_number" of relation "driving_student" violates not-null constraint
Detail: Failing row contains (Peter Parker, null).
2021-08-27 21:36:58.632 ERROR 11388 --- [nio-8080-exec-4] o.a.c.c.C.[.[.[/].[dispatcherServlet] :
Servlet.service() for servlet [dispatcherServlet] in context with path []
threw exception [Request processing failed;
nested exception is org.springframework.dao.DataIntegrityViolationException:
could not execute statement; SQL [n/a];
constraint [driving_instructor_number" of relation "driving_student];
nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement] with root cause
org.postgresql.util.PSQLException: ERROR: null value in column "driving_instructor_number" of relation "driving_student" violates not-null constraint
Detail: Failing row contains (Peter Parker, null).
There are stuff I've tried but most exceptions simply end up with either of those two. All I really wanted to do was insert an instance of DrivingStudent into the database using POST request, with a foreign key connecting it to a DrivingInstructor instance, and then of course, be able to retrieve those data.
I am able to do insert data manually into the database using the statement:
INSERT INTO driving_student VALUES ('Peter Parker', 1);
And I am able to retrieve that data in JSON format using GET method. So far, my only problem really is how to deal with the POST method.
Ok, I just changed/simplified the annotations in DrivingStudent's drivingInstructor JoinColumn field from this:
#ManyToOne(cascade = CascadeType.ALL, targetEntity = DrivingInstructor.class)
#JoinColumn(name = "driving_instructor_id", referencedColumnName = "driving_instructor_name", insertable = false, updatable = false)
private DrivingInstructor drivingInstructor;
to this:
#ManyToOne
#JoinColumn(name = "driving_instructor_id")
private DrivingInstructor drivingInstructor;
and it somehow worked... I have no idea why though.

Unable to Read 2nd Refcursor in a Spring Boot application with Hibernate and Oracle 11g Database

Problem Details
We are working on a Spring Boot application where in we are connecting to Stored Procs (all returning multiple refcursors) using #NamedStoredProcedureQuery for Oracle 11g DB. We are unable to read data from the second cursor at the same time. As soon as we provide the second result class for the 2nd refcursor we are getting an exception titled Invalid Column Name. Reading 1 cursor works fine.
Exception Details
javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException:
Error extracting results from CallableStatement Caused by:
java.sql.SQLException: Invalid column name
Implementation Details
STORED PROCEDURE QUERY
#NamedStoredProcedureQuery (
name = "getSP1Data",
procedureName = "package_name",
resultClasses = {Cursor1Response.class, Cursor2Response.class},
parameters = {
#StoredProcedureParameter(type = Integer.class, mode = ParameterMode.IN, name = "in_param_1"),
#StoredProcedureParameter(type = void.class, mode = ParameterMode.REF_CURSOR, name = "cursor_1"),
#StoredProcedureParameter(type = void.class, mode = ParameterMode.REF_CURSOR, name = "curosr_2"),
#StoredProcedureParameter(type = String.class, mode = ParameterMode.INOUT, name = "in_out_param_2") }
)
CURSOR RESPONSE CLASSES
#Entity
public class Cursor1Response {
#Id
#Column(name = "column_name_1")
private Date column1;
#Column(name = "column_name_2")
private Double column2;
}
#Entity
public class Cursor2Response {
#Id
#Column(name = "column_name_1")
private Date column1;
#Column(name = "column_name_2")
private Double column2;
}
DAO LAYER IMPLEMENTATION (FROM WHERE WE ACTUALLY CALL OUR STORED PROC QUERY)
StoredProcedureQuery query = entityManager.createNamedStoredProcedureQuery("getSP1Data");
// Code for setting all in params
query.getResultList(); // While execution of this line it is
throwing the above mentioned exception
Has anyone worked on such scenario and have any ideas how to fix this exception?
I had the same issue. First I tried downgrading the Oracle JDBC driver from 8 to 6 with no results. After that I changed the annotation with a more programmatic stored procedure definition (note: avoid positional parameters, they cause the same problem...):
EntityManager entityManager = Persistence.createEntityManagerFactory("namehere").createEntityManager();
StoredProcedureQuery spq =
entityManager.createStoredProcedureQuery("YOUR.SP.NAME")
.registerStoredProcedureParameter("name1", String.class, ParameterMode.IN)
.registerStoredProcedureParameter("name2", Integer.class, ParameterMode.OUT)
.registerStoredProcedureParameter("name3", String.class, ParameterMode.OUT)
.registerStoredProcedureParameter("name4", void.class,ParameterMode.REF_CURSOR)
.setParameter(SP_PARAM_MSISDN, "paramval");
spq.execute();

Spring Data REST getting exception when trying to save the data

I new to using Spring data rest , so even though this might be a very basic thing I would appreciate it if someone could point what is the mistake that i made or point me in the right direction .
I have an EmployeeRepository which contains the employee entities.
public interface EmployeeRepository extends CrudRepository<Employee,Long>{
#Query("select emp from Employee emp where emp.employeeId=?1")
Employee findById(String employeeId);
#Query("select emp from Employee emp where emp.officialEmailId = ?1")
Employee findByOfficialEmailId(String officialEmailId);
}
Below is a part of the employee entity delcaration .
public class Employee extends AbstractAuditingEntity{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Version
private Long version;
#Size(min = 3, max = 30)
#NotBlank
#Column(unique=true,nullable=false)
private String employeeId;
#Size(min=3,max = 25)
#NotBlank
#Field(index=Index.YES, analyze=Analyze.NO, store=Store.YES)
private String lastName;
#Size(min=3,max = 25)
#Field(index=Index.YES, analyze=Analyze.NO, store=Store.YES)
#NotBlank
private String firstName;
#Size(min=3,max = 25)
#Field(index=Index.YES, analyze=Analyze.NO, store=Store.YES)
private String middleName;
}
In my service class I needed to get list of employee entities based on a condition and set a common property to all those .I tried it and it did not work so I tried something much simpler , I'm trying to set the middle name of all employees to a common value and save it to the db . Here is the code for it
#Transactional
public void tempFunction(){
Iterable<Employee> empList = employeeRepository.findAll();
for(Employee e : empList){
e.setMiddleName("newMiddleName");
employeeRepository.save(e);
}
}
I'm getting the below exception 2016-02-20 17:59:08.545 ERROR 533 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction] with root cause
java.lang.NullPointerException: null
And the stack trace shows the root cause to be a NullPointerException which I know is not present anywhere near where I'm invoking this code from either in my controller or service . Could someone point if there is any mistake in my code , thanks in advance .

SQL0913 Row or object table in Schema type *FILE in use

I am having a transaction using spring data , and I am trying to do an save operation (insert operation) . [SQL0913] Row or object table in Schema type *FILE in use.
Following is the entity
#Entity
#IdClass(OsytxlId.class)
#Table(name="OSYTXL")
#NamedQuery(name="Osytxl.findAll", query="SELECT o FROM Osytxl o")
public class Osytxl implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name="TLCONO")
private BigDecimal tlcono;
#Id
#Column(name="TLDIVI")
private String tldivi;
#Id
#Column(name="TLLINO")
private BigDecimal tllino;
#Column(name="TLLMTS")
private BigDecimal tllmts;
#Id
#Column(name="TLLNCD")
private String tllncd;
#Column(name="TLTX60")
private String tltx60;
#Id
#Column(name="TLTXID")
private BigDecimal tltxid;
#Id
#Column(name="TLTXVR")
private String tltxvr;
//getter and setters
}
I am using springdata-jpa
And I am calling the following code portion from the service implementation class
Before the following insertion , I need to delete the contents before insert .
Osytxl osytxl = null;
Collection<Osytxl> osytxlList = new ArrayList<Osytxl>();
for (int lineNo = 0; lineNo < lines.length; lineNo++) {
osytxl = new Osytxl();
osytxl.setTlcono(osytxh.getThcono());
osytxl.setTldivi(osytxh.getThdivi());
osytxl.setTltxid(osytxh.getThtxid());
osytxl.setTltxvr(osytxh.getThtxvr());
osytxl.setTllncd(osytxh.getThlncd());
osytxl.setTllmts(new BigDecimal("1437651510403"));
osytxl.setTllino(new BigDecimal(lineNo+1));
osytxl.setTltx60(lines[lineNo]);
osytxlList.add(osytxl);
}
if(osytxlList.size()>0)
osytxlRepository.save(osytxlList);
And I am using JPA repository But I am getting the following exception
org.springframework.orm.jpa.JpaSystemException: org.hibernate.exception.GenericJDBCException: could not execute statement; nested exception is javax.persistence.PersistenceException: org.hibernate.exception.GenericJDBCException: could not execute statement
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:415)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:418)
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:59)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:147)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodIntercceptor.invoke(CrudMethodMetadataPostProcessor.java:122)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at com.sun.proxy.$Proxy107.saveAndFlush(Unknown Source)
........................................................
Caused by: java.sql.SQLException: [SQL0913] Row or object OSYTXL in schema type *FILE in use.
at com.ibm.as400.access.JDError.createSQLExceptionSubClass(JDError.java:877)
at com.ibm.as400.access.JDError.throwSQLException(JDError.java:706)
at com.ibm.as400.access.JDError.throwSQLException(JDError.java:676)
at com.ibm.as400.access.AS400JDBCStatement.commonExecute(AS400JDBCStatement.java:1021)
at com.ibm.as400.access.AS400JDBCPreparedStatement.executeUpdate(AS400JDBCPreparedStatement.java:1825)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:208)
... 127 more
I am using iseries (DB2) .Am I missing something or there anything I need to do extra in persistence.xml . Can anyone help .
I've found on Experts Exchange that this could be due to queries outside of your application, locking the required records.
Adding FOR READ ONLY to your query like this:
SELECT * FROM FILE.TABLE
FOR READ ONLY

sequence does not exist exception using eclipseLink with oracle db

I've got the following JPA entity:
#Entity
#Table(schema = "myschema")
#SequenceGenerator(schema = "myschema", name = "seqGenerator",
sequenceName = "person_s1", allocationSize = 1)
public class Person {
#Id
#GeneratedValue(generator = "seqGenerator", strategy = GenerationType.AUTO)
private long id;
the following exceptions are thrown:
Call: DROP SEQUENCE myschema.person_s1
Query: DataModifyQuery(sql="DROP SEQUENCE myschema.person_s1")
[EL Warning]: 2010-11-01 17:21:51.051--ServerSession(10605044)--Exception [EclipseLink- 4002] (Eclipse Persistence Services - 2.1.1.v20100817-r8050):
org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLException: ORA-02289: sequence does not exist
Error Code: 2289
Call: SELECT myschema.person_s1.NEXTVAL FROM DUAL
Query: ValueReadQuery(sql="SELECT myschema.person_s1.NEXTVAL FROM DUAL")
The sequence is genrated by EclipseLink and the query:
SELECT myschema.person_s1.NEXTVAL FROM DUAL
works fine when used directly...
Any help appreciated
Regards Marcel
the following exceptions are thrown (...)
These traces are generated during schema creation when a particular database object doesn't exist and thus can't be dropped. EclipseLink report such cases as Warning (which are not Error), they can be ignored (you get your sequence, right?).
PS: Why do you use an allocation size of 1, don't you want to benefit from the high/low optimization?
I know this is going to sound really silly, but here it is anyway.
#Entity
#Table(schema = "myschema")
public class Person {
#Id
#SequenceGenerator(schema = "myschema", name = "seqGenerator", sequenceName = "person_s1", allocationSize = 1)
#GeneratedValue(generator = "seqGenerator", strategy = GenerationType.AUTO)
private Long id;
}

Resources