Hibernate - Spring Data JPA One To Many unique constraint across table - postgresql

I have a department and employee table. I need the dept name and employees in the department to be unique such that a new entry for the dept with the same set of employees is given it should throw a unique constraint violation error.
I am not sure how to work this out in hibernate.
I need to have unique constraints across multiple tables.
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
#Entity
#Table(
name="dept"
)
public class DeptEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(nullable = false)
private String name;
#OneToMany(mappedBy = "dep", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Employee> attributes = new ArrayList<>();
}
import javax.persistence.*;
#Entity
#Table(name="emp"
)
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
#ManyToOne(cascade = CascadeType.REFRESH, fetch = FetchType.EAGER)
#JoinColumn(name = "dept_id", referencedColumnName = "id", nullable = false)
private DeptEntity dep;
}

You can use like :
#Column(unique= true)
private String name;

Related

Joining three tables with #OneToMany association

I have three tables.
1.Street (street_id, settlement_entity_id, street_name),
2.Settlement_entity (settlement_entity_id, settlement_id, settlement_name), for example could be community, regional, municipality.. and
3.Settlement (settlement_id, settlement_name), for example could be city, town, township, village....
Relation - Street - Settlement_entity = > onetomany
Relation - Settlement_entity - Settlement = > onetomany
I want when I enter the name of the street, I get the settlement entity as above
as in parentheses and after that the settlement name with characteristics that are not to be the subject of this application, such as for example the house/apartment number, floor, longitude, latitude, altitude of the settlement.
entity
Street.java
package net.javaguides.springboot.entity;
#Entity
#Table(name = "street")
public class Street {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long street_id;
#Column(name = "street_name")
private String street_name;
public Street(String street_name) {
super();
this.street_name = street_name;
}
// getter and setters
entity
Settlement_entity.java
package net.javaguides.springboot.entity;
import javax.persistence.Column;
#Entity
#Table(name = "settlement_entity")
public class SettlementEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long settlement_entity_id;
#Column(name = "settlement_entity_name")
private String settlement_entity_name;
public SettlementEntity(String settlement_entity_name) {
super();
this.settlement_entity_name = settlement_entity_name;
}
// getters and setters
public void setSettlement_entity_name(String settlement_entity_name) {
this.settlement_entity_name = settlement_entity_name;
}
}
entity
Settlement.java
package net.javaguides.springboot.entity;
import javax.persistence.Column;
#Entity
#Table(name = "settlement")
public class Settlement {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long settlement_id;
#Column(name = "settlement_name")
private String settlement_name;
public Settlement(String settlement_name) {
super();
this.settlement_name = settlement_name;
}
// getters and setters
}
I creating according suggestion from -thelearner new linking entity which would be used for mapping that particular table.
entity linking table
StreetSettlementEntitySettlement.java
package net.javaguides.springboot.entity;
import javax.persistence.CascadeType;
public class StreetSettlementEntitySettlement {
#Id
#GeneratedValue
private long id;
#OneToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
#JoinColumn(name = "street_id")
private Street street;
#OneToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
#JoinColumn(name = "settlement_entity_id")
private SettlementEntity settlement_entity;
#OneToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
#JoinColumn(name = "settlement")
private Settlement settlement;
public StreetSettlementEntitySettlement(long id, Street street, SettlementEntity
settlement_entity, Settlement settlement) {
super();
this.id = id;
this.street = street;
this.settlement_entity = settlement_entity;
this.settlement = settlement;
}
}
Directory structure
I saw some proposal from thelearner like this:
It's not clear for me and don't understanding. Where should I put those three classes or should do something else. Repo's is clear.
Any help and explanation would be appreciated. Thank you

Pagerequest object with sort property of the child

How to specify the children's property name while creating the PageRequest object. In the below example, I want to sort based on the name property of the Customer entity which is part of the Order class. I should be able to sort on any of the parent or child field.
Sort.Direction sortDirection = direction
.equalsIgnoreCase("asc") ? Sort.Direction.ASC : Sort.Direction.DESC;
//how to make the `name` property map to `Customer` name
PageRequest pageRequest = PageRequest.of(page, size, sortDirection, "name");
Page<Order> pageResponse = this.orderRepository.findAll(pageRequest);
#Entity
#Table(name = "orders")
public class Order {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne
#JoinColumn(name="customer_id", nullable = false)
#JsonBackReference
private Customer customer;
...
----------
#Entity
#Table(name = "customers")
#NoArgsConstructor
public class Customer implements UserDetails {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#NotEmpty(message = "customer name cannot be empty")
private String name;
#OneToMany(mappedBy = "customer", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JsonManagedReference
private Set<Order> orders;
...

Avoid recursion in one to many relation in jpa entities

I have two entities paymentTransaction and paymentCard as follows. When I fetch paymentTransactions It stuck in infinite call from one to another. I have tried #JsonIgnore, #JsonIdentityInfo and etc to sortout this issue but non of them works. I'm running select query as HQL query like this
FROM PassengersLogArchive as pass_log INNER JOIN " +
"PaymentTransactions as pmt_txn ON pmt_txn.tripId=pass_log.passengersLogId
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.math.BigDecimal;
import java.util.Date;
#Data
#Table(name = "payment_transactions")
#NoArgsConstructor
#Entity
public class PaymentTransactions {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "trip_id")
private Long tripId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "card_id")
private PaymentCards paymentCard;
}
#Data
#Table(name = "payment_cards")
#NoArgsConstructor
#ToString
#Entity
public class PaymentCards {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "passenger_id")
private Long passengerId;
#Column(name = "masked_number")
private String maskedNumber;
#OneToMany(mappedBy = "paymentCard", fetch = FetchType.LAZY)
private List<PaymentTransactions> paymentTransactions;
}

org.postgresql.util.PSQLException: ERROR: insert or update on table violates foreign key constraint

org.postgresql.util.PSQLException: ERROR: insert or update on table "party_custom_fields" violates foreign key constraint "fk21oqkpi7046skme7jce06fxdu"
Below error could help, what need to be done on the code, I have tried few reference, but not helpful.
Detail: Key (custom_field_value)=(11) is not present in table "custom_field_value"
Above is my error while saving.
Party is the class which will have custom fields and it's data
import lombok.Data;
import javax.persistence.*;
import java.util.HashMap;
import java.util.Map;
#Entity
#Data
#Table(name = "party")
public class Party {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#Column(name = "last_name")
private String lastName;
private String email;
private String gender;
#OneToMany(cascade = CascadeType.ALL)
#JoinTable(name = "party_custom_fields",
joinColumns = {#JoinColumn(name = "custom_field")},
inverseJoinColumns = {#JoinColumn(name = "custom_field_value")})
#MapKeyColumn(name = "custom_field_key")
private Map<Long, CustomFieldValue> customField = new HashMap<>();
public Party() {
}
public Party(String name) {
this.name = name;
}
}
Custom fields value model
package org.aeq.multitenant.model;
import lombok.Data;
import javax.persistence.*;
#Data
#Entity
#Table(name = "custom_field_value")
public class CustomFieldValue {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String value;
}
Custom fields model which hold what are the custom fields for the tables
package org.aeq.multitenant.model;
import lombok.Data;
import org.aeq.multitenant.enums.Tables;
import javax.persistence.*;
#Data
#Entity
#Table(name = "custom_field")
public class CustomField {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String type;
private boolean optional;
#Enumerated(EnumType.STRING)
#Column(name = "table_name")
private Tables tableName;
}
Controller function to save
Map<Long, CustomFieldValue> cfMap = new HashMap<>();
for (CustomField cf : customFields) {
if (!partyData.containsKey(cf.getName())) {
return new ApiResult<>(false, "Please provide " + cf.getName() + " custom field of party");
} else {
CustomFieldValue cfv = new CustomFieldValue();
cfv.setValue(partyData.get(cf.getName()).trim());
cfv = customFieldValueRepository.save(cfv);
cfMap.put(cf.getId(), cfv);
}
}
Party party = new Party();
party.setName(partyData.get("name"));
party.setEmail(partyData.get("email").trim());
party.setGender(partyData.get("gender").trim());
party.setLastName(partyData.get("last_name").trim());
party.setCustomField(cfMap);
party = partyRepository.save(party);
please review my code and let me where I am going wrong
If a column has a foreign key constraint, then any entry to that column should be present in the reference table given. If not, then this exception will be thrown.

JPA dataIntegrityViolationException occurs for multiple parents

I am working on simple spring security demo and want to put user and role info into db. Here is the simple structure of my entity.
#Entity
#Table(name = "users")
public class Users {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "user_id")
private Long userId;
#OneToMany(mappedBy = "users", fetch = FetchType.LAZY, orphanRemoval=true, cascade = CascadeType.ALL)
private List<UserRoleMapping> userRoleMapping;
}
//
#Entity
#Table(name = "user_role_mapping")
public class UserRoleMapping {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "user_role_mapping_id")
private Long userRoleMappingId;
#ManyToOne(fetch = FetchType.LAZY)
private Users users;
#ManyToOne(fetch = FetchType.LAZY)
private UserRole userRole;
}
//
#Entity
#Table(name = "users_role")
public class UserRole {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "role_id")
private Long roleId;
#Column(name = "role")
private String role;
#Column(name = "role_desc")
private String roleDesc;
#OneToMany(mappedBy = "userRole", fetch = FetchType.LAZY, orphanRemoval=true)
private List<UserRoleMapping> userRoleMapping;
}
In my use case, I have to make sure when the user is created then I have to insert subsequence userRoleMapping. And If the userRole is removed then the userRoleMapping must be deleted as well.
So I put CascadeType.ALL and orphanRemoval=true in users entity, and orphanRemoval=true in userRole entity.
However, when I run userRoleRepository.delete(userRole). I have dataIntegrityViolationException.
I did some researches on it and understand it is a kind of jpa constrains to make sure we delete the parents (users) as well.
May I ask if there are any workaround for my use case?
Thanks
Here is the solution to my use cases. Instead of using OneToMany in both entity, I should use ManyToMany relationship. And it is quite make sense as I don't care (for now) the mapping in java logic. Here is my code
public class Users {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "user_id")
private Long userId;
#ManyToMany(fetch = FetchType.LAZY, cascade = { CascadeType.MERGE, CascadeType.PERSIST })
#JoinTable
private Set<UserRole> userRole;
}
//
public class UserRole {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "role_id")
private Long roleId;
#Column(name = "role")
private String role;
#Column(name = "role_desc")
private String roleDesc;
#OneToMany(mappedBy = "userRole", fetch = FetchType.LAZY)
private Set<Users> users;
}