Hibernate cascade doesn't remove child when deleting parent - java

Hibernate cascade remove doesn't remove child when deleting parent.
causing this error:
ORA-02292: violated integrity constraint (owner.constraintname)- child record found.
Here are my entities:
#Entity
#Table(name = "FLIGHT_MAP_REGION")
#Audited
public class FlightMapRegion extends AbstractBWSModel {
private static final long serialVersionUID = 1L;
#Id
#SequenceGenerator(name = "FLIGHT_MAP_REGION_ID_GENERATOR", sequenceName = "SEQ_FLIGHT_MAP_REGION", allocationSize=1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "FLIGHT_MAP_REGION_ID_GENERATOR")
private Long ID;
#Column(name = "CODE")
private String code;
// bi-directional one-to-many association to FlightMapRegionI18n
#OneToMany (mappedBy = "flightMapRegion", fetch = FetchType.EAGER, cascade=CascadeType.REMOVE, orphanRemoval=true)
#Fetch(value = FetchMode.SUBSELECT)
#NotAudited
private List<FlightMapRegionI18n> flightMapRegionI18ns;
//getters&setters
and:
#Entity
#Table(name = "FLIGHT_MAP_REGION_I18N")
#Audited
public class FlightMapRegionI18n extends AbstractBWSModel implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#SequenceGenerator(name = "FLIGHT_MAP_REGION_I18N_ID_GENERATOR", sequenceName = "SEQ_FLIGHT_MAP_REGION_I18N", allocationSize=1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "FLIGHT_MAP_REGION_I18N_ID_GENERATOR")
private Long ID;
#Column(name = "NAME")
private String name;
// bi-directional many-to-one association to flightMapRegion
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "FLIGHT_MAP_REGION_CODE", referencedColumnName="CODE")
#AuditJoinTable
private FlightMapRegion flightMapRegion;
//getters & setters
I want to delete any child FlightMapRegionI18n records when deleting the parent FlightMapRegion record.
Note that these tables are not connected via id, they are connected like this:
FOREIGN KEY (FLIGHT_MAP_REGION_CODE)
REFERENCES FLIGHT_MAP_REGION (CODE)
And I don't want to add ON DELETE CASCADE on database level. I want to achive this programmatically in java.

Related

How should I map my one table to another using JPARepositoy?

I have a table schema like this. Notification can be of 2 types : twitter or fb
For each notification, there will be 1 row in notification table and 1 in either twitter_post/ fb_post.
Each table have auto sequence id generator.
FBPost and TwitterPost is mapped via notification_id (PK)
I have created entity class like this:
#Entity
#Table(name = "notification")
public class Notification {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "not_id_sequence")
private String id;
#Column(name = "description")
private String description;
#OneToOne(mappedBy = "notification")
private FBPost fbPost;
#OneToOne(mappedBy = "notification")
private TwitterPost twitterPost;
}
#Entity
#Table(name = "fb_post")
public class FBPost {
#Id
#Column(name = "post_id")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "post_fid_sequence")
private Long postId;
#Column(name = "post_content")
private String postContent;
#OneToOne
private Notification notification;
}
#Entity
#Table(name = "twitter_post")
public class TwitterPost {
#Id
#Column(name = "post_id")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "post_tid_sequence")
private Long postId;
#Column(name = "post_content")
private String postContent;
#OneToOne
private Notification notification;
}
I am using JpaRepository to save into the database. But not getting any row into fb_post or twitter_post table.
Am i doing it wrong in entity class.
Try adding #JoinColumn(name = "notification_id", referencedColumnName = "notification_id") below #oneToOne in TwitterPost and FBPost class for the notification variable
Looks like you are missing cascade. Try to add cascade = CascadeType.ALL into #OneToOne of the parent entity - Notification:
#Entity
#Table(name = "notification")
public class Notification {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "not_id_sequence")
private String id;
#Column(name = "description")
private String description;
#OneToOne(mappedBy = "notification", cascade = CascadeType.ALL)
private FBPost fbPost;
#OneToOne(mappedBy = "notification", cascade = CascadeType.ALL)
private TwitterPost twitterPost;
}
For more information I would recommend to read hot to map one-to-one relationship.

Repeated column in mapping for entity in #OneToOne unidirectional mapping

Consider the following database structure
I need to implement unidirectional one to one mapping like that (structure is simplified):
#Entity
#Table(name = "entity")
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#OneToOne
#JoinColumn(name = "customer_info", nullable = false)
private CustomerInfo customerInfo;
#OneToOne
#JoinColumn(name = "customer_credentials", nullable = false)
private CustomerCredentials customerCredentials;
// getter, setters etc
}
#Entity
#Table(name = "customer_info")
public class CustomerInfo {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
// getter, setters etc
}
#Entity
#Table(name = "customer_credentials")
public class CustomerCredentials {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
// getter, setters etc
}
But somehow hibernate unable to differentiate that those joins are from different tables and throws such error:
Caused by: org.hibernate.MappingException: Repeated column in mapping for entity: com.example.Customer column: customer_id (should be mapped with insert="false" update="false")
Important notice: I do not want to use #OneToOne(mappedBy = "customer") because I need cascade save functionality
You can use #JoinTable instead of #JoinColumn to solve your problem:
#Entity #Table(name = "entity") public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#OneToOne(cascade = CascadeType.ALL, targetEntity = CustomerInfo.class)
#JoinTable(name = "customer_info", inverseJoinColumns = {#JoinColumn(name = "customer_id", nullable = false)})
private CustomerInfo customerInfo;
#OneToOne(cascade = CascadeType.ALL, targetEntity = CustomerCredentials.class)
#JoinTable(name = "customer_credentials", inverseJoinColumns = {#JoinColumn(name = "customer_id", nullable = false)})
private CustomerCredentials customerCredentials;
// getter, setters etc }
#Entity #Table(name = "customer_info") public class CustomerInfo {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
// getter, setters etc }
#Entity #Table(name = "customer_credentials") public class CustomerCredentials {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
// getter, setters etc }
You could change the cascade strategy to any strategy you need. I just left CascadeType.ALL there as an example.

Hibernate / JPA: How to map two #Immutable entities (views of same table) with another entity by same parameter

There is a table ORDERS from which were created views ORDER_VIEW_A and ORDER_VIEW_B.
I have created entity classes OrderViewA and OrderViewB where in each of them is mapping on entity named 'TransactionRecord'.
It is #OneToOne relationship.
There is column ORDER_ID in TRANSACTION_RECORD table and field orderId in TransactionRecord entity.
Field orderId is same for OrderViewA.id and for OrderViewB.id, cause views are selected from the same table.
My question is, how to map in Hibernate two views in OneToOne relationship with another entity by same field.
My code looks like this and it doesn't work in any way, Hibernate always end up with:
org.hibernate.AnnotationException: Referenced property not a
(One|Many)ToOne: com.example.app.model.TransactionRecord.orderId in
mappedBy of com.example.app.model.views.OrderViewA.orderViewA
#Entity
#Immutable
#Table(name = "ORDER_VIEW_A")
public class OrderViewA {
#Id
#Column(name = "id")
private Long id;
...
#OneToOne(mappedBy = "orderId", fetch = FetchType.LAZY)
private IntegrationRecord orderARecord;
...
}
#Entity
#Immutable
#Table(name = "ORDER_VIEW_B")
public class OrderViewB {
#Id
#Column(name = "id")
private Long id;
...
#OneToOne(mappedBy = "orderId", fetch = FetchType.LAZY)
private IntegrationRecord orderBRecord;
...
}
#Entity
#Table(name = "TRANSACTION_RECORD")
public class TransactionRecord {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "order_id")
private Long orderId;
...
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "order_id")
private OrderViewA orderViewA;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "order_id")
private OrderViewB orderViewB;
...
}

#OneToOne with shared key between three tables

I have three entities who share the same primary key. There is a bidirectional one-to-one relationship between the Account and Provider entity, where the previously named entities share their primary key, but at the same time the Provider entity shares the primary key with the GlobalRating entity, where there is a unidirectional relationship between them. I must say that I am using hibernate with MySQL as a database:
Account Entity:
#Entity
#Table(name="account")
#Getter
#Setter
#JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "email")
public class Account implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy= GenerationType.AUTO, generator="native")
#GenericGenerator(name = "native", strategy = "native")
#Column(name="id")
private int id;
#OneToOne(mappedBy = "account", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
private Provider provider;
}
Provider Entity:
#Entity
#Table(name="provider")
#Getter
#Setter
#JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "providerId")
public class Provider implements Serializable, Comparable<Provider>{
private static final long serialVersionUID = 1L;
#Id
#Column(name="pk_account$provider")
#GeneratedValue(generator="native")
#GenericGenerator(name="native", strategy="foreign",parameters=#Parameter(name="property", value="account"))
private int providerId;
#OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#PrimaryKeyJoinColumn
private Account account;
#OneToOne(fetch=FetchType.LAZY, cascade = CascadeType.ALL, optional = false)
#PrimaryKeyJoinColumn
private GlobalRating globalRating;
}
GlobalRating Entity:
#Entity
#Table(name="global_rating")
#Getter
#Setter
public class GlobalRating implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#Column(name="pk_provider$global_rating")
#GeneratedValue(generator="native")
#GenericGenerator(name="native", strategy="foreign",parameters=#Parameter(name="property", value="globalRating"))
private int globalRatingId;
}
The problem that I have is when creating an Account with a Provider and a GlobalRating. I am sure that the bidirectional mapping between Account and Provider works, but the problem lies in the mapping of the entity Provider and the entity GlobalRating. I have tried it in several ways but it does not work. So, how is this case mapped correctly in hibernate?
I appreciate that you can help me with this.

Hibernate Composite Key Join

I'm trying to use Spring Data to perform joined queries but one of my tables has a Composite Key and I'm not sure how to map the entities.
Here is an analogy of the data model:
table: device
pk=model_id
pk=serial_id
...
table: device_settings
pk=device_settings_id
fk=model_id
fk=serial_id
...
Here is an analogy of the code, which doesn't compile due to a "mappedby" attribute that is isn't present.
#Entity
#Table(name = "device_settings")
public class DeviceSettings {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "device_settings_id")
private Long id;
// Pretty sure this is the problem
#OneToMany(targetEntity = Device.class, mappedBy = "deviceKey", cascade = {CascadeType.MERGE}, fetch = FetchType.EAGER)
#JoinColumns({
#JoinColumn(name = "model_id", referencedColumnName = "model_id"),
#JoinColumn(name = "serial_id", referencedColumnName = "serial_id")})
private List<Device> devices;
}
#Entity
#Table(name = "device")
public class Device {
#Id
private DeviceKey deviceKey;
}
...
}
#Embeddable
public class DeviceKey implements Serializable {
private static final long serialVersionUID = -1943684511893963184L;
#Column(name = "model_id")
private Long modelId;
#Column(name = "serial_id")
private Short serialId;
}
Associations marked as mappedBy must not define database mappings like #JoinTable or #JoinColumn
To achieve your scenario you have to define #ManyToOne:
#ManyToOne(cascade = {CascadeType.MERGE}, fetch = FetchType.EAGER)
#JoinColumns({
#JoinColumn(name = "model_id", referencedColumnName = "model_id"),
#JoinColumn(name = "serial_id", referencedColumnName = "serial_id")})
private Device device;
This will end up model_id, serial_id, device_settings_id
or
Define #JoinColumn in Device Entity
Entities:
DeviceSettings :
#Entity
#Table(name = "device_settings")
public class DeviceSettings {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "device_settings_id")
private Long id;
#OneToMany( mappedBy = "deviceSettings", cascade = {CascadeType.MERGE}, fetch = FetchType.EAGER)
private List<Device> devices;
}
Device Entity :
#Entity
#Table(name = "device")
public class Device {
#EmbeddedId
private DeviceKey deviceKey;
#ManyToOne
#JoinColumn(name="device_settings_id")
private DeviceSettings deviceSettings;
//getters and setters
}
Note : you can decide which is the owner of the relationship and put your mappings accorindly either One Device has many device settings or other way around.

Categories

Resources