Search code examples
javajpaeclipselink

EclipseLink how to delete orphans entities from the "one side" in a ManyToOne relationship


After searching an answer, I have seen the @PrivateOwner annotation but it doesn't solve my issue.

I'm using EclipseLink

here is the issue: I have 2 Entities related with a 1:n bidirectional relationship.

A ComponentEntity can be related to one TransferDetailsEntity

A TransfertDetailsEntity is related to one or multiple ComponentEntity.

what I want to achieve is: when I delete the last Component referencing a TransfertDetails, this TransfertDetails should be deleted. Same if I change the last reference to a TransfertDetails.

in short : As soon as a TransfertDetails is not referenced by any Component, it should be deleted.

As a workaround I call this method :

@Override
public void removeOrphanTransfer() {
    for (TransferDetailsEntity transfer : transferDetailsRepository.findAll()) {
        if (transfer.getComponents().isEmpty()) {
            transferDetailsRepository.delete(transfer);
        }
    }
}

That works but it's not really efficient since it search through the entire table. and it's quite ugly...

here is the (simplified) code for Entities :

TransfertDetailsEntity:

@Entity
@Table(name = TransferDetailsEntity.TABLE_NAME)
@Getter
@Setter
@NoArgsConstructor
public class TransferDetailsEntity extends AbstractEntity {

    [...]
    @Id
    @Column(name = ID, nullable = false)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected Long id;

    [...]

    @OneToMany(mappedBy = "transferDetails")
    private List<ComponentEntity> components;

    [...]

}

ComponentEntity:

@Entity
@Table(name = ComponentEntity.TABLE_NAME, uniqueConstraints = @UniqueConstraint(name = ComponentEntity.TABLE_NAME
        + AbstractEntity.SEPARATOR + AbstractEntity.CONSTRAINT,
        columnNames = { ComponentEntity.COLUMN_NAME_SERIAL, ComponentEntity.COLUMN_NAME_TYPE }))
@Getter
@Setter
@ToString(callSuper = true, exclude = { "parent" })
@NoArgsConstructor
public class ComponentEntity extends AbstractEntity {

    [...]

    @Id
    @Column(name = ID, nullable = false)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected Long id;

    [...]

    @ManyToOne(cascade = CascadeType.PERSIST)
    @JoinColumn(name = COLUMN_TRANSFER_DETAILS)
    private TransferDetailsEntity transferDetails;

    [...]

}

As mentioned earlier, @PrivateOwner on the @OneToMany annotation (in TransfertDetailsEntity) doesn't work...

any help appreciated


Solution

  • There is no automatic JPA or EclipseLink feature that will do this for you, your application will have to handle this.

    The easiest I can think of is on removal of a ComponentEntity, get the referenced TransfertDetailsEntity and check its components list to see if it has other ComponentEntity references and remove it if it does not. You should be removing each ComponentEntity reference from the TransfertDetailsEntity.components list when you delete it anyway, so this list should be up to date and not incur any database hits.