Spring JPA save() inserting instead of updating - spring

I have a table in below format
Customer:
ID PK
value1
value2
address
I have unique constraint for value1 and value2.
While saving/updating I will not be having value for ID
So here is my service class code to update customer:
#Transactional
public void saveCustomer(String value1,String value2, String address) {
Customer customer = customerRepository.findByValue1AndValue2(value1,value2).orElse(new Customer());
customer.setValue1(value1);
customer.setValue2(value2);
customer.setAddress(address);
customerRepository.save(customer);
}
I am getting "Cannot insert duplicate key row in object error."
When I get the customer object using findByValue1AndValue2, it will have id orrect? so it should do update not insert
Adding my customer class:
#Entity
#Table(name = "customer")
#Data
#NoArgsConstructor
#AllArgsConstructor
#EntityListeners(AuditingEntityListener.class)
public class Customer{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "id")
private Integer id;
#Column(name="value1")
private String value1;
#Column(name="value2")
private String value2;
#Column(name="address")
private String address;
#CreatedDate
#Column(name="created_date", nullable = false, updatable = false)
private Date created_date;
#LastModifiedDate
#Column(name="updated_date")
private Date updated_date;
}
I have added annotation #EnableTransactionManagement
Is there any thing specific need to be done
Please help me with this issue.
Thanks in advance

Related

JPA merge table

I have table employee
#Entity
#Table(name = "employee")
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="emp_id")
private Long id;
#Column(name="emp_name")
private String empName;
#Column(name="emp_mail")
private String empMail;
#Column(name="emp_no")
private String empNo;
#Column(name="emp_salary")
private Long empSalary;
#Column(name="type_id")
private Long typeId;
}
In addition, I have table employeetype whose primary key type id is in employee table
How i am able to get response containg type_name not type_id in java data jpa for api using jparepository.
how to join table data.

JPARepository CPRQ modified does not save full object

I have modified the design of CPRQ a bit to help my database pattern
I have an Employee table and a Department table. Both have common properties
#Column(name="tenantIDPKFK")
private Integer tenantIdpkfk;
#Column(name="status")
private Integer status;
So I created a base class ABaseEntity like below
public class ABaseEntity {
public ABaseEntity() {
}
public ABaseEntity(int tenantIdpkfk, int status) {
this.tenantIdpkfk = tenantIdpkfk ;
this.status = status ;
}
#Column(name="tenantIDPKFK")
private Integer tenantIdpkfk;
#Column(name="status")
private Integer status;
I have extended EmployeeEntity with ABaseEntity
#Entity
#Table(name = "employee")
public class EmployeeEntity extends ABaseEntity{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "first_name")
#NotEmpty(message = "Please provide a name")
#NotBlank
private String firstName;
My CommandHandler runs the following code
EmployeeEntity savedEmployeeEntity = this.employeeRepository.saveAndFlush(employee);
this.mediator.emit(new EmployeeCreatedEvent(savedEmployeeEntity.getId()));
Database saved the object, but only id, firstname. Does not save tenant and status columns.
I know I am missing something silly. Please help.
EDIT
Adding #MappedSuperclass to the ABaseEntity class fixed the issue.
#MappedSuperclass
public class ABaseEntity {...}
Database saved the object, but only id, firstname. Does not save
tenant and status columns.
By default JPA doesn't consider the parent class in the orm (object-relational mapping) of the current class.
You have to specify on the parent class #Inheritance with the strategy to use or use the default one.
For example :
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class ABaseEntity {...}
More info here.

Spring Data JPA ManyToOne query null

I've started to learn Spring Boot, I've created two entities Invoice and YearDate
When I try to search by year(id), in my log query I got null (see this part of log query)
http://localhost:8080/appapi/invoices/search/findByYearId?year=1
from invoice invoice0_ left outer join year_date yeardate1_ on invoice0_.year_id=yeardate1_.id where yeardate1_.id is null limit?
I'm using Lombok also for getters and setters
Here are all my class entities, SQL tables, and JpaRepository interface :
SQL foreign key :
KEY `fk_year` (`year_id`),
CONSTRAINT `fk_year` FOREIGN KEY (`year_id`) REFERENCES `YearDate` (`id`)
YearDate class :
#Entity
#Table(name="YearDate")
#Data
public class YearDate {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "year_value")
private String yearValue;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "year")
private Set<Invoice> invoices;
}
Invoice class:
#Entity
#Table(name="invoice")
#Data
public class Invoice {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "name")
private String name;
#ManyToOne
#JoinColumn(name = "year_id", nullable = false)
private YearDate year;
#Column(name = "description")
private String description;
}
**And The Invoice Interface:**
#CrossOrigin("http://localhost:4200")
public interface InvoiceRepository extends JpaRepository<Invoice, Long> {
Page<Invoice> findByYearId(#RequestParam("year") Long id, Pageable page);
}
Work for me.
try to extract call in rest controller and log params
#GetMapping(value = "/invoices")
public Page<Invoice> getInvoices(#RequestParam("yearId") Long yearId) {
Page<Invoice> byYearId = invoiceRepository.findByYearId(yearId, PageRequest.of(0, 10));
return byYearId;
}
public interface InvoiceRepository extends JpaRepository<Invoice, Long> {
Page<Invoice> findByYearId(Long id, Pageable page);
}
#ManyToOne
#JoinColumn(name = "year_id", nullable = false)
#JsonIgnoreProperties("invoices")
private YearDate year;
#OneToMany(mappedBy = "year")
#JsonIgnoreProperties("year")
private Set<Invoice> invoices;
Generated SQL :
Hibernate:
select
invoice0_.id as id1_0_,
invoice0_.description as descript2_0_,
invoice0_.name as name3_0_,
invoice0_.year_id as year_id4_0_
from
invoice invoice0_
left outer join
year_date yeardate1_
on invoice0_.year_id=yeardate1_.id
where
yeardate1_.id=? limit ?
Hibernate:
select
yeardate0_.id as id1_5_0_,
yeardate0_.year_value as year_val2_5_0_
from
year_date yeardate0_
where
yeardate0_.id=?
-> ADD #JsonIgnoreProperties("invoices") and #JsonIgnoreProperties("year") to entities to avoid infinite json recusrsion.
I've disabled Lombok and it works
try pass him a Year object not id is better
#CrossOrigin("http://localhost:4200")
public interface InvoiceRepository extends JpaRepository<Invoice, Long> {
Page<Invoice> findByYear(YearDate year, Pageable page);
}
and in your service get this year
for exemple I create a getYears method in service:
#Service
public class YearService{
#Autowired
private YearRepository yearRepository;
#Autowired
private InvoiceRepository invoiceRepository;
getYears(idYear:Long){
YearDate yearParam=yearRepository.findById(id).get();
Page<Invoice> invoices=invoiceRepository.findByYear(yearParam,YourPagination)
}
}

How to make composite Foreign Key part of composite Primary Key with Spring Boot - JPA

I have a problem with the historization of objects in the database.
the expected behavior of the save JpaRepository method is : Insert in the two tables idt_h and abo_h
But the current behavior is Insert in the idt_h table and update in the abo_h table.
#Data
#Entity
#Table(name = "ABO_H")
#AllArgsConstructor
#NoArgsConstructor
public class AboOP {
#Id
#Column(name = "ABO_ID")
private String id;
#Column(name = "ABO_STATUT")
private String statut;
#Column(name = "ABO_DATE_STATUT")
private Instant date;
#Column(name = "ABO_CoDE")
private String code;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumns({
#JoinColumn(name = "IDC_ID", referencedColumnName = "IDC_ID"),
#JoinColumn(name = "DATE_HISTO", referencedColumnName = "DATE_HISTO")
})
private IdtOP idtOP;
}
#Data
#Entity
#Table(name = "IDT_H")
#AllArgsConstructor
#NoArgsConstructor
public class IdtOP {
#AttributeOverrides({
#AttributeOverride(name = "id",
column = #Column(name = "IDC_ID")),
#AttributeOverride(name = "dateHisto",
column = #Column(name = "DATE_HISTO"))
})
#EmbeddedId
private IdGenerique idtId = new IdGenerique();
//Other fields
}
#Data
#AllArgsConstructor
#NoArgsConstructor
#Embeddable
public class IdGenerique implements Serializable {
private String id;
private Instant dateHisto;
}
I think that the class IdGenerique which groups the id and dateHisto is not well invoked for the table abo_h ??
thanks in advance
When you use the save() method, entityManager checks if the entity is new or not. If yes, the entity will be saved, if not, it'll be merged
If you implement your Entity Class with the inteface Persistable, you can override the method isNew() and make it returns True. In that case the save() method will persist, and not merge, your entity.

i'm getting null value in a child table as a foreign key of parent table using spring data rest or spring data jpa accosiation

enter image description here In this image first address for empId 1 and last two records are empid 2 (empid 2 haveing to address)
file:///home/user/Pictures/fk.png
#Entity
#Table(name = "Employee")
public class Employee {
#Id
#GeneratedValue
private Integer id;
private String name;
private Integer sal;
#OneToMany(cascade = CascadeType.ALL,mappedBy="employee")
private List<Address> addresses;
//getter setter
Child entity
#Entity(name="Address")
public class Address {
#Id
#GeneratedValue
private Integer aid;
private String city;
private String state;
#ManyToOne
#JoinColumn(name="id")
private Employee employee;
//getter setter
Repository
#Repository
#RepositoryRestResource(path="employee")
public interface EmployeeRepo extends JpaRepository<Employee,Integer> {
}
Input from RestClient
{
"name":"rdhe",
"sal":"20000",
"addresses":[{
"city":"hyd",
"state":"ts"
}]
}
if i use spring data jpa then code will be
// jpa Repository
public interface EmployeeRepo extends JpaRepository<Employee,Integer> {
}
// EmployeeServer class
#Service
public class EmployeeService {
#Autowired
EmployeeRepo employeeRepo;
public void saveEmployee(Employee employee){
employeeRepo.save(employee);
}
}
// controller
#RestController
public class EmployeeController {
#Autowired
EmployeeService employeeService;
#PostMapping(path="/save")
public void saveEmp(#RequestBody Employee employee){
employeeService.saveEmployee(employee);
}
}
if i'll use spring-data-rest at that time no need to create employeeService and controller class
I was getting the same problem until JsonManagedReference came to my rescue.
Try changing your entities to include them like this:
In the Employee Entity:
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy ="employee")
#JsonManagedReference
private List<Address> addresses;
In the Address Entity:
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id", nullable = false, updatable = false, insertable =true)
#JsonBackReference
private Employee employee;
I was not able to find why it works this way, so please let me know if you come to know :)
It is probably due to the fact that your mentioning #JoinColumn(name="id"). The name attribute in #JoinColumn defines the name of the foreign key field in the child table. Since you are specifying foreign key column as id on hibernate, it could be the issue. Please update it to the same name(ie fk_empid) as specified in database, it should work...

Resources