How to delete a record from a table the table reference is in another table using hibernate - postgresql

I am newbie on Hibernate,
I want to perform deletion on one table the current table is referenced to another table.
Ex: Client_Loan is my main table i want to perform deletion on this, and the another table is 'Loan_Details'. the loan_details table contains the foreign_Key reference to the client_loan id.
i want to perform delete on client_loan table, if i delete client loan table the references in another table also want to delete at one shot using Hibernate can any one tell me how to perform.
Thanks in advance.

You must be having classes like below
#Entity
#Table(name="Client_Loan")
public class ClientLoan {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
#OneToMany(cascade = CascadeType.ALL,
mappedBy = "client", orphanRemoval = true)
private List<Loan_Details> loans = new ArrayList<>();
public void setName(String name) {
this.name = name;
}
public List<Loan_Details> getComments() {
return loans;
}
public void addComment(Loan_Details loan) {
loans.add(loan);
}
}
below for load details
#Entity
#Table(name="Loan_Details ")
public class LoanDetails {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne
private Client_Loan client;
public void setPost(Client_Loan post) {
this.post = post;
}
public String getReview() {
return review;
}
public void setReview(String review) {
this.review = review;
}
}
Now in ClientLoan in OnetoMany mapping cascade = CascadeType.ALL
it means when you will delete CleintLoan all the LoanDetails will be deleted automatically

First delete from Loan_Details then Client_loan
First delete from Loan_Details then Client_loan
int id = 2;
Session session=getSession();
String hql = "delete from Loan_Details where client_loanid = :id";
session.createQuery(hql).setString("id", new Integer(id)).executeUpdate();
hql = "delete from Client_Loan where clientid = :id";
session.createQuery(hql).setString("id", new Integer(id)).executeUpdate();

Related

cascade persist results in null column value for a ManyToMany entity

Owner:
#Entity
public class Strategy implements Serializable {
#Id
#GeneratedValue
private Long id;
#ManyToMany(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST})
#JoinTable(name = "StrategyHost", joinColumns = {#JoinColumn(name = "strategyId")}, inverseJoinColumns = {#JoinColumn(name = "hostId")})
private Set<Host> hostName;
}
Related entity:
#Entity
public class Host {
#Id
#GeneratedValue
private Long id;
#Column(unique = true)
private String name;
#ManyToMany(mappedBy = "hostName")
private List<Strategy> strategies;
public Host(String name) {
this.name = name;
}
}
Test:
#Test
#Transactional(propagation = Propagation.NOT_SUPPORTED)
public void testStrategyWithHosts() {
Strategy s = new Strategy();
Set<Host> hosts= new HashSet<>();
hosts.add(Host.builder().name("aaa").build());
hosts.add(Host.builder().name("bbb").build());
s.setHostName(hosts);
Strategy saved= strategyDao.save(s);
Set<Host> hostName = saved.getHostName();
}
debug shows the persisted saved object having Host:
Where are name values? However, if I add merge in cascade type array, name are valued. Why insert (not update managed entities) operation for related entities must have merge cascade type? Although log shows nothing suspicious:
insert into strategy...
insert into host...
insert into host...
update strategy ...
insert into strategy_host ...
insert into strategy_host ...

JPA: How to fill related entity after the master is inserted

I have two tables called SL_DOCUMENT and SL_PROPOSE. The SL_DOCUMENT has its own ID (ID_DOCUMENT) and a foreign key to SL_PROPOSE (ID_PROPOSE). The SL_PROPOSE ID column is ID_PROPOSE. The particularity is that SL_PROPOSE ID value is actually the SL_DOCUMENT.ID_DOCUMENT value. i.e., after a new SL_DOCUMENT is inserted, the related SL_PROPOSE should be inserted with the SL_DOCUMENT.ID_DOCUMENT as ID and later the same value should be used in SL_DOCUMENT.ID_PROPOSE column.
I did my JPA mapping as follows:
#Entity
#Table(name = "SL_DOCUMENT")
public class DocumentORM {
#Id
#Column(name = "ID_DOCUMENT")
#SequenceGenerator(name = "SEQ_SL_DOCUMENT", sequenceName = "SEQ_SL_DOCUMENT")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_SL_DOCUMENT")
private Long id;
#OneToOne(mappedBy = "document", cascade = { CascadeType.PERSIST })
// #JoinColumn(name = "ID_PROPOSE", updatable = false)
private ProposeORM propose;
// ...
}
#Entity
#Table(name = "SL_PROPOSE")
public class ProposeORM {
#Id
#Column(name = "ID_PROPOSE")
private Long id;
#MapsId
#OneToOne
#JoinColumn(name="ID_PROPOSE")
private DocumentORM document;
// ...
public ProposeORM(DocumentORM document) {
super();
this.document = document;
this.document.setPropositura(this);
}
}
To create the new instances of of DocumentORM and ProposeORM:
DocumentORM document = new DocumentORM();
ProposeORM propose = new ProposeORM(document);
And finally to insert the new Document with ProposeORM:
this.documentoDAO.insert(document);
When I really insert a document, according the snippets above, I see in the console (Websphere 8.5) the INSERT commands for the SL_DOCUMENT, SL_PROPOSE running correctly. However, when I see the tables, the column SL_DOCUMENT.ID_PROPOSE is still NULL. Even If I uncomment the #JoinColumn annotation over DocumentORM.propose, the SL_DOCUMENT.ID_PROPOSE column continues to be not filled.
The ideal would be if SL_DOCUMENT had a discriminator column and ProposeORM was a DocumentORM subclass, using the JOINED InheritanceType (there are other tables with the same kind of relationship with SL_DOCUMENT). However, these are legacy tables and it is not possible to change it.
So, what is the alternative to fill SL_DOCUMENT.ID_PROPOSE? A workaround I was thinking is fill this column using a native SQL. Do you have better ideas?
Thanks,
Rafael Afonso
The solution I see is to make ProposeORM's ID not auto-generated, since you always want it to have the ID of the document it's linked to, AND still have a join column in the document table:
#Entity
#Table(name = "SL_DOCUMENT")
public class DocumentORM {
#Id
#Column(name = "ID_DOCUMENT")
#SequenceGenerator(name = "SEQ_SL_DOCUMENT", sequenceName = "SEQ_SL_DOCUMENT")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_SL_DOCUMENT")
private Long id;
#OneToOne
#JoinColumn(name = "ID_PROPOSE")
private ProposeORM propose;
// ...
}
#Entity
#Table(name = "SL_PROPOSE")
public class ProposeORM {
#Id
#Column(name = "ID_PROPOSE")
private Long id;
#OneToOne(mappedBy = propose)
private DocumentORM document;
// ...
public ProposeORM(DocumentORM document) {
super();
this.id = document.getId();
this.document = document;
this.document.setPropositura(this);
}
}
You'll have to persist the document first, flush the EntityManager to make sure the document has a generated ID, and then persist the propose and set it into the document.

#ManyToOne Lazy loading not working

I've seen other posts about this problem, but have found no answer to my own troubles. I have
#Entity
#Table(name= ServerSpringConstants.COMPANY)
public class Company implements Serializable {
private static final long serialVersionUID = -9104996853272739161L;
#Id #GeneratedValue(strategy=GenerationType.AUTO)
#Column (name = "companyID")
private long companyID;
#OneToMany (targetEntity = Division.class, cascade = {
CascadeType.PERSIST,
CascadeType.MERGE,
CascadeType.REFRESH},
fetch = FetchType.EAGER)
#JoinTable (name = "companyDivisionJoinTable",
joinColumns = #JoinColumn(name="companyID"),
inverseJoinColumns = #JoinColumn(name="divisionID")
)
private Set<Division> divisions = new HashSet<>();
public long getCompanyID() {
return companyID;
}
public Set<Division> getDivisions() {
return divisions;
}
public void setDivisions(Set<Division> divisions) {
this.divisions = divisions;
}
}
On the other side:
#Entity
#Table(name= ServerSpringConstants.DIVISION)
public class Division implements Serializable {
private static final long serialVersionUID = -3685914604737207530L;
#Id
#GeneratedValue(strategy= GenerationType.AUTO)
#Column(name = "divisionID")
private long divisionID;
#ManyToOne
(fetch = FetchType.LAZY, optional = false, targetEntity = Company.class,
cascade = {CascadeType.PERSIST, CascadeType.MERGE
}
)
#JoinColumn(name="companyID", referencedColumnName = "companyID")
private Company company;
public long getDivisionID() {
return divisionID;
}
public void setDivisionID(long divisionID) {
this.divisionID = divisionID;
}
public Company getCompany() {
return company;
}
public void setCompany(Company company) {
this.company = company;
}
}
Yet for some reason, LAZY loading not working. I'm using JPA. I'm calling back the companies, and their enclosing divisions from within a 'User' class -- the pertinent part
#ManyToMany (targetEntity = Company.class,
cascade={
CascadeType.PERSIST,
CascadeType.MERGE,
CascadeType.REFRESH},
fetch=FetchType.EAGER )
#JoinTable (
name="companyUserJoinTable",
joinColumns=#JoinColumn(name="userID"),
inverseJoinColumns=#JoinColumn(name="companyID")
)
private Set<Company> company = new HashSet<>();
I've searched out existing threads, and have tried adding various suggestions, but nothing has helped!
Any help appreciated.
Thanks!
Since you are loading the divisions set eagerly (with fetch = FetchType.EAGER) and you have a bidirectional association, divisions will be initialized with the parent reference to company. I can't see any problem with it. Jpa loaded the full object tree because you just told it so. A company contains divisions which contain a back reference to the company that loaded them.
To understand it better, since the reason for lazy loading is to reduce the data loaded from database, the owning company is already loaded in session for the divisions, so why not setting the association too?
The #ManyToOne association on the other side takes effect if you load divisions first.
To be more correct with your mapping add also a #MappedBy attribute to the one part of the association. This does not affect fetching behavior but will prevent double updates to the database issued by both ends of the association.

EntityExistsException When Attempting Bulk Delete With OpenJPA

I have three classes: Location, MTFCC, and BorderPoint.
Location has a unidirectional #ManyToOne relationship with MTFCC, which is intended only as a Lookup table. No cascading is defined.
Location also has a bidirectional #ManyToOne/#OneToMany with BorderPoint. Since I want all associated BorderPoint objects to delete when I delete a Location, I set cascadetype.ALL on the Location side of the relationship.
Unfortunately, an EntityExistsException is being thrown when I attempt to delete a location:
org.apache.openjpa.persistence.EntityExistsException: Cannot delete or update
a parent row: a foreign key constraint fails (`mapmaker`.`BORDERPOINT`,
CONSTRAINT `BORDERPOINT_ibfk_1` FOREIGN KEY (`LOCATIONID`) REFERENCES `LOCATION`
(`LOCATIONID`)) {prepstmnt 21576566 DELETE t0, t1 FROM LOCATION t0 INNER JOIN
MTFCC t1 ON t0.MTFCCID = t1.MTFCCID WHERE (t0.STATEFP = ? AND t1.MTFCCCODE = ?)
[params=?, ?]} [code=1451, state=23000]
[ERROR] FailedObject: DELETE t0, t1 FROM LOCATION t0 INNER JOIN MTFCC t1 ON
t0.MTFCCID = t1.MTFCCID WHERE (t0.STATEFP = ? AND t1.MTFCCCODE = ?)
[java.lang.String]
It looks like it's attempting to delete the associated MTFCC object which I do NOT want to happen. I do, however, want the associated BorderPoint objects to be deleted.
Here is the code (chopped down a bit):
#SuppressWarnings("unused")
#Entity
#Table(name="LOCATION")
#DetachedState(enabled=true)
public class Location implements Serializable, IsSerializable, Cloneable {
private Long id;
private String stateGeoId;
private MTFCC mtfcc;
private List<BorderPoint> borderPointList;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="LOCATIONID")
public Long getId() {
return id;
}
#ManyToOne
#JoinColumn(name="MTFCCID")
public MTFCC getMtfcc() {
return mtfcc;
}
#OneToMany(cascade = CascadeType.ALL, mappedBy = "location", fetch = FetchType.EAGER)
public List<BorderPoint> getBorderPointList() {
return borderPointList;
}
}
#Entity
#Table(name = "BORDERPOINT")
#DetachedState(enabled = true)
public class BorderPoint implements Serializable, IsSerializable {
private Long id;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="BORDERID")
public Long getId() {
return id;
}
#ManyToOne(targetEntity = Location.class)
#JoinColumn(name="LOCATIONID")
public Location getLocation() {
return location;
}
}
#Entity
#Table(name = "MTFCC")
public class MTFCC implements Serializable, IsSerializable {
private Long id;
private String mtfccCode;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "MTFCCID")
public Long getId() {
return id;
}
// etc
}
And, for good measure, here is the deletion code:
#Override
#Transactional
public int removeByStateGeoIdAndMtfcc(String stateGeoId, String mtfccCode) throws RepositoryException {
EntityManager em = entityManagerFactory.createEntityManager();
String jpaQuery = "DELETE FROM Location L where L.stateFP = ?1 AND L.mtfcc.mtfccCode = ?2";
int affectedRows = 0;
Query query = em.createQuery(jpaQuery).setParameter(1, stateGeoId).setParameter(2, mtfccCode);
try {
em.getTransaction().begin();
affectedRows = query.executeUpdate();
em.getTransaction().commit();
} catch (Exception e) {
//log.debug("Exception: ", e);
throw new RepositoryException(e);
}
em.close();
return affectedRows;
}
Hopefully I copied all relevant parts... can anyone assist?
You aren't reading the error message correctly. It says that the deletion is forbidden because of the foreign key constraint between BorderPoint and Location.
The cascade delete would work if you used em.remove(location) to delete your Location. Using a delete query like you're doing won't automagically delete the BorderPoints before deleting the location.
Either load them and remove them using em.remove, or execute other delete queries before to delete the BorderPoints.

How to correctly do a manytomany join table in JPA?

I need 3 entities: User, Contract (which are a many to many relation) and a middle entity: UserContract (this is needed to store some fields).
What I want to know is the correct way to define the relationships between these entities in JPA/EJB 3.0 so that the operations (persist, delete, etc) are OK.
For example, I want to create a User and its contracts and persist them in a easy way.
Currently what I have is this:
In User.java:
#OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
private List<UserContract> userContract;
In Contract.java:
#OneToMany(mappedBy = "contract", fetch = FetchType.LAZY)
private Collection<UserContract> userContract;
And my UserContract.java:
#Entity
public class UserContract {
#EmbeddedId
private UserContractPK userContractPK;
#ManyToOne(optional = false)
private User user;
#ManyToOne(optional = false)
private Contract contract;
And my UserContractPK:
#Embeddable
public class UserContractPK implements Serializable {
#Column(nullable = false)
private long idContract;
#Column(nullable = false)
private String email;
Is this the best way to achieve my goals?
Everything looks right. My advice is to use #MappedSuperclass on top of #EmbeddedId:
#MappedSuperclass
public abstract class ModelBaseRelationship implements Serializable {
#Embeddable
public static class Id implements Serializable {
public Long entityId1;
public Long entityId2;
#Column(name = "ENTITY1_ID")
public Long getEntityId1() {
return entityId1;
}
#Column(name = "ENTITY2_ID")
public Long getEntityId2() {
return entityId2;
}
public Id() {
}
public Id(Long entityId1, Long entityId2) {
this.entityId1 = entityId1;
this.entityId2 = entityId2;
}
}
protected Id id = new Id();
#EmbeddedId
public Id getId() {
return id;
}
protected void setId(Id theId) {
id = theId;
}
}
I omitted obvious constructors/setters for readability. Then you can define UserContract as
#Entity
#AttributeOverrides( {
#AttributeOverride(name = "entityId1", column = #Column(name = "user_id")),
#AttributeOverride(name = "entityId2", column = #Column(name = "contract_id"))
})
public class UserContract extends ModelBaseRelationship {
That way you can share primary key implementation for other many-to-many join entities like UserContract.