Spring data jpa does not update existing row (Oracle) when using #sequencegenerator - oracle

New to spring data JPA. I have sequence created in oracle table. I am using JPARepository saveall() method to save the data. Inserts work without any problem but when i try to update any existing rows in the table it always tries to insert throwing unique constraint error since i have unique index created for that table.
Entity Class
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "generator1")
#SequenceGenerator(sequenceName = "emp_seq", name = "generator1",allocationSize = 1)
#Column(name = "USER_ID")
private Long id;
Save method invocation
public void persistEmployees(List<Employee> employees) {
employeeRepo.savaAll(employees);
}
Repository class
#Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> { }
How can i tell JPA to look for existing row before inserting? Any help is much appreciated!!!

In My Humble Opinion;
Using "Exists" condition-check as "sub-query" for all constrained columns, before Update will solve this.

Related

JPA Entity class which is not mapped to any table

I am using a entity class for mixing two/three table columns in one entity to hold an outcome of SYS_REFCURSOR in oracle
This allows me to have single class which is not mapped to any table but it still is an Entity
#Data
#Entity
#NoArgsConstructor
class EmployeeDetails {
#Id
#Column("emp_id")
String empId;
#Column("job_name")
String jobName;
#Column("dept_name")
String deptName;
//Future requirement
//String updatedBy
}
Now I have an additional requirement, to add who last modified the employee table, I don't want modify the procedure now, the procedure is being re-used in another background procedure and batch jobs.
My question is, is it possible to use #ManyToOne on this class which is obviously not mapped to any table
If not how do avoid manually looping a child array list, is there a ready made option in JPA or spring boot to achieve that.
Or what will be the smartest/recommended way to bring the below Entity into this class
#Data
#Entity
#NoArgsConstructor
#Table(name="app_users")
class AppUsers {
#Id
#Column(name="user_id")
String userId;
#Column
String userName;
}
#Transient, check how this annotation works it will resolve the issue, you need to understand working of #Transient
My spring boot 2.6.2 EntityManager code is as follows
q = em.createStoredProcedureQuery("MY_PROC",EmployeeDetails.class);
q.registerStoredProcedureParameter("OUT_REFC", void.class, ParameterMode.REF_CURSOR);
q.execute();
q.getResultList()
I have modified my class EmployeeDetails as below
#Data
#Entity
#NoArgsConstructor
class EmployeeDetails {
#Id
#Column("emp_id")
String empId;
#Column("job_name")
String jobName;
#Column("dept_name")
String deptName;
#OneToOne
#JoinColumn(
name="user_id",
referencedColumnName="emp_id",
insertable=false,
updatable=false,
nullable=true
)
AppUsers updatedBy;
}
The log prints Hibernate two times one after one as below, first it calls the proc and then it calls the select query, so, I did not wrote that SQL myself, the JPA layer is taking care of it
Hibernate:
{call MY_PROC(?)}
Hibernate:
select
...
...
from app_users
where user_id=?
so, my expectation achieved and I am getting the values

Unable to insert into table in hibernate

I am trying to create new table and join with ManyToOne relation with my existing table
below is my implementation
New table
#Entity(name="request_city_id")
#Table(uniqueConstraints={#UniqueConstraints{columnNames={"request_id","cityId"})})
#Data
#NoArgsConstructor
#FieldDefault(level=AccessLevel.PRIVATE)
public class RequestCityId{
#GenratedValue(strategy=SEQUENCE, generator="seq_req_city_id")
#SequenceGenerator(name="seq_req_city_id", allocationSize=1)
#Column(name="rc_id")
#Id
long id;
#ManyToOne
#JoinColumn(name="request_id")
Request request;
String cityId;
String status
}
Existing table
#Entity(name="request")
#Data
#NoArgsConstructor
#FieldDefault(level=AccessLevel.PRIVATE)
public class Request{
String frequency
#GenratedValue(strategy=SEQUENCE, generator="seq_req_d")
#SequenceGenerator(name="seq_req_id", allocationSize=1)
#Column(name="request_id")
#Id
long id;
#OneToMany(cascade={ PERSIST, MERGE}, mappedBy="request", fetch=EAGER)
Set<RequestCityId> requestCityIds;
}
but when I am trying to insert into my new table I see my hibernate query gets stuck and just gets timed out after sometime, I am not sure what I am doing wrong here? If I just kep cascade type MERGE then getting
Hibernate Error: a different object with the same identifier value was already associated with the session
First you should create an getters and setters method to each entity.
Request Class
Request City Id Class
this code creates the tables and also saves the data into the table.
Using #Data in entity classes in not recommended because it may cause some problems with jpa as mentioned here.

Hibernate doesn't return manually INSERTed rows

I'm having an issue with my jpa repository doesn't return rows that I've manually inserted into the database (Oracle) via good old SQL
Insert into SYSTEM.USER (ID,CREDENTIALS,ISADMIN) values (USERSEQ.nextval,'foo',1);
My Jpa Repository
#RepositoryRestResource
public interface UserRepository extends JpaRepository<User, Long> {}
User entity
#Data
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "idgen")
#SequenceGenerator(initialValue = 1, allocationSize = 1, name = "idgen", sequenceName = "userseq")
private Long id;
#NotNull
private String credentials;
private boolean isAdmin;
}
The super weird thing is that entries that I've inserted via the REST interface works!
So if I create:
User A via REST API
User B via SQL statement
User C via REST API
The result of GET /api/users is A, C
After pulling out all my hair. I think I've narrowed it down to the Flashback feature Oracle has. As only A and C has entries in the Flashback. So Hibernate must do some magic behind the scene.
So my question is. How do I insert a row using SQL so it get a flashback entry also.
If the flashback thing isn't the problem. How do I make Hibernate return all the rows then?
while you are executing the SQL query in Oracle Sql Developer that time it is working own session. and JPA is working own session. i.e. JPA is not able to access the SQL query's records.
solution
Insert into SYSTEM.USER (ID,CREDENTIALS,ISADMIN) values (USERSEQ.nextval,'foo',1);
after that just fire the COMMIT command in Oracle Sql Developer.
it is working for me.

Relational database foreign keys in Spring Boot JPA/Hibernate

I'm using Spring Boot JPA with Gradle. I'm struggling to find a guide that I can follow which focusses on creating a relational database with the correct Syntax for Spring Boot. I had a go but I get this error
No property idTestCase found for type TestRun!
I want TestRun and TestData entities with a OneToOne relationship with each other, and a TestCase entity that has a OneToMany relationship with TestRun. I reckon that TestRun should contain the foreign keys for TestData and TestCase.
Many times I make changes and it will not build, and when it does build the tables do not look correct, this is what I created:
#Entity
public class TestRun {
#Id #GeneratedValue(strategy = GenerationType.AUTO)
private long testRunId;
private Boolean result;
#OneToOne #JoinColumn(name="testData_id")
private TestData testData;
#ManyToOne #JoinColumn(name="testCase_id")
private TestCase testCase;
}
#Entity
public class TestCase {
#Id #GeneratedValue(strategy = GenerationType.AUTO)
private long testCaseId;
private String name;
private String description;
#OneToMany(cascade=CascadeType.ALL, mappedBy="testCase",targetEntity=TestRun.class)
private Collection<TestRun> testRun;
}
#Entity
public class TestData {
#Id #GeneratedValue(strategy = GenerationType.AUTO)
private long testDataId;
#OneToOne(cascade=CascadeType.ALL, mappedBy="testData",targetEntity=TestRun.class)
private TestRun testRun;
}
From the guides it isn't clear to me what goes in #JoinColumn(name= some say it needs to link to a field on your POJO and some say it doesn't. If I create the foreign key field in my POJO then I get two foreign key fields in the database table and if I don't it doesn't build at all.
For example from the error I can infer it wants me to add the following fields to TestRun:
private long idTestCase;
private long idTestData;
But then my database appears as:
SELECT * FROM TEST_RUN;
TEST_RUN_ID
ID_TEST_CASE
ID_TEST_DATA
RESULT
TEST_CASE_ID
TEST_DATA_ID
(no rows, 3 ms)
I tried setting #JoinColumn(name= to the name of the primary key field on the other side of the relationship but again it did not build.
Many thanks
I found the guide at JBoss to be the most helpful in describing the different mappings.

I need help for persisting into oracle database

There is a problem about generating id while persisting into database.
I added the following code to my jpa entity file, however I'm getting 0 for personid.
#Id
#Column(unique=true, nullable=false, precision=10, name="PERSONID")
#SequenceGenerator(name="appUsersSeq", sequenceName="SEQ_PERSON", allocationSize=1)
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator = "appUsersSeq")
private long personid;
EjbService:
#Stateless
public class EjbService implements EjbServiceRemote {
#PersistenceContext(name = "Project1245")
private EntityManager em;
#Override
public void addTperson(Tperson tp) {
em.persist(tp);
}
}
0 is default value for long type. The id will be set after invoking select query for the related sequence, which commonly is executed when you persist the entity. Are you persisting the entity? In case yes, post the database sequence definition to check it.

Resources