I have a OneToMany relationship, I can insert records but can not delete them, when I try to delete it runs into " a foreign key constraint fails" error. I have used cascade delete orphan as following but does not work yet.
Parent class has following getter for its member
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.OneToMany;
#Entity
#DynamicUpdate
public class User extends Employee{
private string userli;
privae List<Message> messagelist();
.....
#OneToMany(fetch = FetchType.LAZY,cascade = CascadeType.REMOVE)
public List<Message> getMessagelist() {
return messagelist;
}
Member class has following getter for its parent
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
......
#ManyToOne
public User getReciever() {
return reciever;
}
I used following annotation as well but did not work
#Cascade(org.hibernate.annotations.CascadeType.DELETE)
My hibernate dependency is as following
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>4.2.1.Final</version>
<type>jar</type>
</dependency>
My code to remove the message
Message message = (Message) session.get(Message.class, id);
session.delete(message);
tx.commit();
Try to change the cascade = cascadeType.ALL
and check
#OneToMany(fetch = FetchType.LAZY,cascade = CascadeType.ALL)
public List<Message> getMessagelist() {
return messagelist;
It might work but not sure
There are a few ways to work with an OneToMany relationship. One of the most common way would be like:
#OneToMany(mappedBy="receiver", CascadeType.REMOVE)
public List<Message> getMessagelist() {
return messagelist;
}
....
#ManyToOne
public User getReciever() {
return reciever;
}
Note that fetch = FetchType.LAZY is the default you do not really need to specify it.
Additionally, you may need to recreate you tables because the db constraint has been created already. Do not trust 100% on hbm2ddl.auto=update in this case. I would suggest dropping the relevant tables (Message, Reciver, and Receiver_Message or Message_Receiver). Next, you can use hbm2ddl.auto=update.
I hope it helps.
Cheers
Try adding following annotations. It worked for me.
#OneToMany(mappedBy="receiver", cascade=CascadeType.ALL, fetch=FetchType.LAZY)
#Cascade(value=org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
public Set<Message> getMessagelist() {
return messagelist;
}
I am using entity manager remove method and it works for me. I am using Set instead of List, which is a efficient way, in my opinion.
Delete orphan annotation is just for telling hibernate that if "I remove entity from MessageList and try to merge User then you can safely delete Message"
#Cascade(value=org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
Related
I am trying to do a simple insertion into my database using Spring boot. When I run my program, I get the error 'could not extract ResultSet'. But I am not looking to extract anything out, I am just purely inserting.
This is my model code:
import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.Table;
#Entity(name = "calendar")
#Table(name = "TB_EVENT")
public class Calendar {
#Id
#GeneratedValue
#JoinColumn(name = "EventID")
private int eventId;
#JoinColumn(name = "Privacy")
private String privacy;
#JoinColumn(name = "EventCode")
private String eventCode;
#JoinColumn(name = "Subject")
private String subject;
#JoinColumn(name = "Location")
private String location;
My service implementation class:
#Override
public void add(Calendar calendar) {
// TODO Auto-generated method stub
logger.info("invoked insertevent function in calendarServiceImpl");
logger.info(calendar.getPrivacy());
logger.info(calendar.getAllDay());
logger.info(calendar.getEventCode());
logger.info(calendar.getSubject());
logger.info(calendar.getReminder());
logger.info(calendar.getLocation());
logger.info(calendar.getStartTime());
logger.info(calendar.getEndTime());
logger.info(calendar.getRecur());
logger.info(calendar.getRemarks());
calendarRepository.save(calendar);
}
I am using the .save() and in my database I have set the id to be auto incremental. Anybody know what went wrong?
Thanks guys, I managed to solve the problem by adding #GeneratedValue(strategy = GenerationType.IDENTITY)
Try to change annotations above fields to #Column.
#JoinColumn is used to indicate the relationship and ownership of the relationship. I guess what you need is #Column annotation.
So replace all #JoinColumn's with #Column would fix the problem.
To see what #JoinColumn does please refer
Using #JoinColumn instead of #Column is first issue that anyone can see from sky high. Please change it to #Column as Hibernate docs suggest. Putting #JoinColumn does not map your field to database in any situation whatsoever.
Also "could not extract ResultSet" is not helpful at all you should have posted your stacktrace instead of only few words.
I am using Cuba Framework with Java JPQL
I have a relationship of:
Transaction_Sets
Transactions
Where
Transaction Entity
#ManyToOne
#JoinColumn(name = "TRANSACTION_SET_ID")
#OnDelete(DeletePolicy.DENY)
protected Transaction_Set transaction_Set;
Transaction_Set entity
#OneToMany(mappedBy = "transaction_Set", cascade = CascadeType.REMOVE)
#OnDeleteInverse(DeletePolicy.DENY)
protected List<Transaction> transactions;
I have tried many combinations of # but for some reason it is not working. All I want it to do is:
Stop the deletion of a transaction if it belongs to a Transaction_Set.
Whenever I try and delete the transaction it
deletes it and removes it from the transaction_set.
Delete all transactions of a transaction_set when the transacion_set is deleted.
Number (2) is working. Number (1) I can't solve...
Have been pulling my hair out over this for the past day.
Am I going about this right? I think it might be something to do with how the Cuba Framework is set up.
An obvious setup would be the following:
// Transaction
#OnDelete(DeletePolicy.DENY)
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "TRANSACTION_SET_ID")
protected TransactionSet transactionSet;
// TransactionSet
#OnDelete(DeletePolicy.CASCADE) // won't work
#OneToMany(mappedBy = "transactionSet")
protected List<Transaction> transactions;
But it won't work because your requirements are contradictory: DENY policy on Transaction will prevent CASCADE deletion from the TransactionSet side. Probably the problem cannot be solved on the ORM level with #OnDelete and #OnDeleteInverse annotations, but you can implement one of the restrictions in an AfterDeleteEntityListener which is run when ORM has already done all its job.
So the mapping should be as follows (keep only the first restriction):
// Transaction
#OnDelete(DeletePolicy.DENY)
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "TRANSACTION_SET_ID")
protected TransactionSet transactionSet;
// TransactionSet
#OneToMany(mappedBy = "transactionSet")
protected List<Transaction> transactions;
And the entity listener (unfortunately you have to use plain SQL here):
package com.company.sample.listener;
import com.haulmont.bali.db.QueryRunner;
import com.haulmont.cuba.core.Persistence;
import com.haulmont.cuba.core.global.TimeSource;
import com.haulmont.cuba.core.global.UserSessionSource;
import com.haulmont.cuba.core.sys.persistence.DbTypeConverter;
import org.springframework.stereotype.Component;
import com.haulmont.cuba.core.listener.AfterDeleteEntityListener;
import java.sql.Connection;
import java.sql.SQLException;
import com.company.sample.entity.TransactionSet;
import javax.inject.Inject;
#Component("sample_TransactionSetEntityListener")
public class TransactionSetEntityListener implements AfterDeleteEntityListener<TransactionSet> {
#Inject
private TimeSource timeSource;
#Inject
private UserSessionSource userSessionSource;
#Inject
private Persistence persistence;
#Override
public void onAfterDelete(TransactionSet entity, Connection connection) {
QueryRunner queryRunner = new QueryRunner();
DbTypeConverter dbTypeConverter = persistence.getDbTypeConverter();
try {
queryRunner.update(connection,
"update SAMPLE_TRANSACTION set DELETE_TS = ?, DELETED_BY = ? where TRANSACTION_SET_ID = ?",
new Object[]{
dbTypeConverter.getSqlObject(timeSource.currentTimestamp()),
userSessionSource.getUserSession().getCurrentOrSubstitutedUser().getLoginLowerCase(),
dbTypeConverter.getSqlObject(entity.getId())
});
} catch (SQLException e) {
throw new RuntimeException("Error deleting related transactions ", e);
}
}
}
I have a Record entity that maintains a #ManyToOne relation with Product_Category table and Price_Category table. The record entity also maintains a #OneToMany association with another table called PendingRecords.
Currently this is working perfectly for hibernate save/persist, in which all the associated tables also get modified when specific conditions are met. The problem is these associated entities are also getting considered on hibernate update/delete which is not what I intended to do. I want to restrict these entites from getting considered and allow change only on insert.
Following are the entity class mappings
Record.java
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Table;
#Entity
#Table(name = "ITEM_RECORDS")
public class Record {
-------------------------
#ManyToOne(optional=false)
#JoinColumn(name = "PRICE_CATEGORY", referencedColumnName="price_category", nullable=false)
private PriceCategory price_category;
#ManyToOne(optional=false)
#JoinColumn(name = "PRODUCT_CATEGORY", referencedColumnName="product_category", nullable=false)
private ProductCategory product_category;
#OneToOne(mappedBy="record", cascade = CascadeType.ALL)
private PendingRecords pendingRecord;
----------------------
(getter setter methods)
-----------------------
Following are the associated tables
PriceCategory.java
#Entity
#Table(name = "PRICE_CATEGORY")
public class PriceCategory{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "PRICE_CATEGORY")
private String price_category;
#Column(name = "DESCRIPTION")
private String description;
----------------------------
(getter-setters)
----------------------------
ProductCategory.java
#Entity
#Table(name = "PRODUCT_CATEGORY")
public class ProductCategory {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID")
private Long id;
#Column(name = "PRODUCT_CATEGORY")
private String product_category;
#Column(name = "DESCRIPTION")
private String description;
----------------------------
(getter-setters)
----------------------------
and finally,
PendingRecords.java
#Entity
#Table(name = "PENDING_RECORDS")
public class PendingRecords{
#Id
#Column(name = "PENDING_RECORD_NO")
#GeneratedValue(generator="gen")
#GenericGenerator(name="gen", strategy="foreign",parameters=#Parameter(name="property", value="record"))
private Long pending_record_id;
----------------------
#OneToOne
#PrimaryKeyJoinColumn
private Record record;
-------------------------
(getters-setters)
-------------------------
The entity associations are working fine when I perform the insert (hibernate persist/save). The problem is when I try to update the Record, hibernate is trying to update all the associated entries also like
select
this_.RECORD_NO as REC_REC1_1_3_,
this_.PRICE_CATEGORY as PRICE_CA10_1_3_,
this_.PRODUCT_CATEGORY as PRODUCT11_1_3_,
pricecatego2_.id as id1_0_0_,
pricecatego2_.PRICE_CATEGORY as PRICE_CAT2_0_0_,
pricecatego2_.DESCRIPTION as DESCRIPT3_0_0_,
productcat3_.ID as ID1_3_1_,
productcat3_.DESCRIPTION as DESCRIPT2_3_1_,
productcat3_.PRODUCT_CATEGORY as PRODUCT_3_3_1_,
pendingrec4_.PENDING_RECORD_NO as REC_REC1_2_2_,
---------------------------
from
ITEM_RECORDS this_
inner join
PRICE_CATEGORY pricecatego2_
on this_.PRICE_CATEGORY=pricecatego2_.PRICE_CATEGORY
inner join
PRODUCT_CATEGORY productcat3_
on this_.PRODUCT_CATEGORY=productcat3_.PRODUCT_CATEGORY
left outer join
PENDING_RECORDS pendingrec4_
on this_.PENDING_RECORD_NO=pendingrec4_.PENDING_RECORD_NO
where
this_.PENDING_RECORD_NO=?
What should be done to prevent considering these entities for join operations while updating Record entity? Because this is an additional overhead and also generates ClassCastException. I need associated entites to be changed only during persit or save and not during update or delete.
I am getting the following error during update
Servlet.service() for servlet dispatcher threw exception: java.lang.ClassCastException: com.myapps.models.PriceCategory cannot be cast to java.io.Serializable
Should I specify CascadeType? Or should i use hibernate CascadeType instead of JPA's which I am currently using for PendingRecords? Or is there another way? Please help me resolve this.
Thanks in advance.
I need associated entites to be changed only during persit or save
and not during update or delete
If, once the related entities are set at persist time, they should never be overwritten with another entity instance, use #JoinColumn(updatable=false).
Note that because of Hibernate's flush operation order, it the related entities do not already exist, you might need to save them first, flush the EntityManager, and only then save the top-level entity.
What should be done to prevent considering these entities for join
operations while updating Record entity?
Try #ManyToOne(fetch=LAZY). I am not entirely sure this will work during a merge, though, as there are many reasons for Hibernate to fetch related entities during a merge. If it doesn't work, you might need to write a custom update query.
I just updated OpenJPA from version 1.2 to 2.2 and many of my JUnits failed. Most of them because ManyToOne relation changed behavior. Lets say we have two entities
package org.my;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.ManyToOne;
#Entity
public class Many {
#ManyToOne(fetch = FetchType.LAZY, optional = false)
private One one;
public One getOne() {
return one;
}
public void setOne(One one) {
this.one = one;
}
}
and
package org.my;
import java.util.List;
#Entity
public class One {
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "one")
private List<Many> many;
public List<Many> getMany() {
return many;
}
public void setMany(List<Many> many) {
this.many = many;
}
}
When I Create One object and set to it List of Many, than persist and commit I got an exception like this
org.apache.openjpa.persistence.InvalidStateException: The field "one" of instance "org.my.Many#4d9cfefb" contained a null value; the metadata for this field specifies that nulls are illegal.
I thought that OpenJPA cat find One object and put it into Many.one field, am I wrong? If not how can I achieve this?
Every Many object in the List of One object should be setOne first before you save it
Using JPA and Hibernate
I have an entity class
#Entity
#Table(name = "ROLES")
public class Role implements Serializable
{
#Column
private List<String> tubes;
// another fields .setters, getters
}
Every String in List tubes - is one row from another table (TUBES).
Table ROLES has an OneToMany relationship with TUBES.
A can make another Entity Tubes and map table TUBES on Entity Tubes. But how I can make this without another entity?
Edit:
I made
#ElementCollection
#CollectionTable(name = "TUBES", joinColumns = #JoinColumn(name = "role_id"))
#Column(name = "tube")
private ArrayList<String> tubes;
Deploy on JBoss. And in runtime I get SQLGrammarException
Query created by JPA is:
/* SELECT r FROM Role r WHERE r.name = ? */ select role0_.AA_ID as AA1_0_, role0_.ROLNAME as ROLNAME0_, role0_.role as PID4_0_ from PIDDB_PID_ROLE role0_ where role0_.ROLNAME=?
17:17:14,661 ERROR [JDBCExceptionReporter] ORA-00904: "ROLE0_"."tube": invalid identifier
You can use #ElementCollection mapping I think this is what are you looking for.
#ElementCollection(fetch=FetchType.LAZY)
#CollectionTable(name="TUBES", joinColumns=#JoinColumn(name="role_id"))
#Column(name="tube")
private List<String> tubes;
Update:
dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.0-api</artifactId>
<version>1.0.0.Final</version>
</dependency>
**Update2:**
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.Table;