I followed https://vladmihalcea.com/the-best-way-to-map-a-onetomany-association-with-jpa-and-hibernate/ to map One To Many Relationship
But I'm getting problem to remove orphan.
I'm followed Other answers
To make parent null for child, but I don't have child to set its parent to null.
I'm using Session#saveOrUpdate
hibernate specific, In DB I've 3 children, and from view I've 2 children to be updated and want to remove 3rd or last one, How to deal with that situation?
My Code snippet as follows:
Entity Class SRS
@Entity
@Table(name="srs")
public class SRS implements Serializable {
[...]
@OneToMany( mappedBy="srs"/*, cascade=CascadeType.ALL*/, orphanRemoval=true )
@Cascade(value={CascadeType.SAVE_UPDATE, CascadeType.REMOVE, CascadeType.REFRESH, CascadeType.MERGE})
private List<SrsRequirement> srsRequirements = new ArrayList<>();
public void addRequirement( SrsRequirement srsRequirement ) {
this.srsRequirements.add( srsRequirement );
srsRequirement.setSrs( this );
}
public void removeRequirement( SrsRequirement srsRequirement ) {
this.srsRequirements.remove( srsRequirement );
srsRequirement.setSrs( null );
}
[...]
}
Entity Class SrsRequirement
@Entity
@Table( name="srs_requirement" )
public class SrsRequirement implements Serializable {
[...]
@ManyToOne( fetch=FetchType.LAZY )
@JoinColumn( name="srs_id" )
private SRS srs;
[...]
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
SrsRequirement other = (SrsRequirement) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
}
Code To save and Update from DAO
@Override
public boolean saveOrUpdateSRS( SRS srs ) {
Session session = null;
Transaction transaction = null;
boolean isSaved = false;
List<SrsRequirement> srsRequirements = srs.getSrsRequirements();
try {
session = getSession();
transaction = session.beginTransaction();
session.saveOrUpdate( srs );
session.flush();
srs.setSrsRequirements( session.get( SRS.class, srs.getId() ).getSrsRequirements() );
for( SrsRequirement srsRequirement : srs.getSrsRequirements() ) {
System.out.println( srsRequirement.toString() );
if( !srsRequirements.contains( srsRequirement ) )
srs.removeRequirement( srsRequirement );
}
if( transaction!= null && transaction.getStatus().equals(TransactionStatus.ACTIVE) )
transaction.commit();
isSaved = true;
} catch ( Exception ex ) {
} finally{
}
return isSaved;
}
Update
I have solved this by session.clear()
, and then session.load()
, and get all requirements
check them and then remove orphan.
Following is working code snippet
session = getSession();
transaction = session.beginTransaction();
session.saveOrUpdate( srs );
session.flush();session.clear();
srs = session.load( SRS.class, srs.getId() );
for( Iterator<SrsRequirement> iterator = srs.getSrsRequirements().iterator(); iterator.hasNext(); ) {
SrsRequirement srsRequirement = iterator.next();
// System.out.println( srsRequirement.toString() );
if( !srsRequirements.contains( srsRequirement ) ) {
// srs.removeRequirement( srsRequirement );
iterator.remove();
srsRequirement.setSrs( null );
}
}
But the problem with this code, is it issues multiple select statements, which should be optimized
Instead of doing this should I execute separate HQL
query to delete rest of srsRequirements
, this will execute single query then
Or any other solution ?