0

I have a simple @ManyToOne and @OneToMany relation between Profile and Link entities. Changes applied in any attribute of those entities are being save/updated thought ProfileRepository.save(profile). In these two cases everything works fine, in case a new Link is add to the Profile.links a new Link is saved to DB, the same if I change an existent link, the modified values from this Link are updated in DB.

What I was expecting to happen when I remove an existent Link form Profile list, is that the same Link would be removed from DB also, but it is not happening.

What am I missing here?

@Entity
@Table(name = "profiles")
public class Profile {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  @Column(name = "user_id", unique = true)
  private Long userId;

  @OneToMany(mappedBy = "profile", cascade = CascadeType.ALL,  fetch = FetchType.LAZY)
  private List<Link> links = new ArrayList<>();

  public void addLink(Link link) {
    links.add(link);
    link.setProfile(this);
  }

// ...

.

@Entity
@Table(name = "links")
public class Link {

   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   private Long id;

   @NotEmpty(message = "Description cannot be empty")
   private String description;

   @NotEmpty(message = "Link cannot be empty")
   private String url;

   @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
   @JoinColumn(name = "profile_id", nullable = false)
   private Profile profile;

// ...

.

public ProfileDTO updateProfile(ProfileDTO profileDTO) {

   Optional<Profile> optProfile = profileRepository.findByUserId(profileDTO.getUserId());

   Profile profile = optProfile
        .orElseThrow(() -> new UserNotFoundException(profileDTO.getUserId()));

   List<Link> links = profileDTO.getLinks()
     .stream()
     .map(l -> aLink()
         .withId(l.getId())
         .withDescription(l.getDescription())
         .withUrl(l.getUrl())
         .build())
     .collect(toList());

   profile.addLinks(links);
   profile.setDescription(profileDTO.getDescription());

   return ProfileDTOBuilder.from(profileRepository.saveAndFlush(profile));
}

.

@Repository
public interface ProfileRepository extends JpaRepository<Profile, Long> {
    Optional<Profile> findByUserId(Long userId);
}

UPDATE

If I run the same code using a Test class and persisting Profile entity with TestEntityManager, it works as expected. Links are removed from memory database.

    entityManager.persist(profile);
    entityManager.flush();

1 Answers1

0

What I was expecting to happen when I remove an existent Link form Profile list, is that the same Link would be removed from DB also, but it is not happening.

JPA doesn't work this way, you have to actually remove the entity.

With Hibernate though you can use the org.hibernate.annotations.CascadeType.DELETE_ORPHAN

See Hibernate deleting orphans when updating collection

Jens Schauder
  • 77,657
  • 34
  • 181
  • 348