0

Sitiuation: trying to remove a person that has a collection of persons(friends). Ofcourse i don't want the friends to be delete so i have to be carefull with that.

code for Person:

@Entity
public class Person {

private String naam, voornaam, email, password;

@Id
private String username;
private String status;

@ManyToMany
private Collection<Person> vrienden;

@OneToMany(orphanRemoval = true)
private Collection<Post> posts;

@Enumerated(EnumType.STRING)
private Role role;

public Person(String naam, String voornaam, String email, String password, String username) {
    setNaam(naam);
    setEmail(email);
    setStatus("online");
    setVoornaam(voornaam);
    setPassword(password);
    setUsername(username);
    vrienden = new HashSet<>();
    posts = new HashSet<>();
    role = Role.USER;
}

public static void addFriend(Person a, Person b) {
    a.addFriend(b);
    b.addFriend(a);
}

private void addFriend(Person b) {
    this.vrienden.add(b);
}

public static void deleteFriend(Person a, Person b) {
    a.deleteFriend(b);
    b.deleteFriend(a);
}

private void deleteFriend(Person a) {
    this.vrienden.remove(a);
}

public Collection<Person> getFriends() {
    return vrienden;
}

public Role getRole() {
    return this.role;
}

public void setRole(Role role) {
    this.role = role;
}

@NotNull(message = "{error.no.name}")
@Size(min = 2, message = "{error.invalid.namesize}")
public String getNaam() {
    return naam;
}

public void setNaam(String naam) {

    this.naam = naam;
}

@NotNull(message = "{error.no.surnaam}")
@Size(min = 2, message = "{error.invalid.surnamesize}")
public String getVoornaam() {
    return voornaam;
}

public void setVoornaam(String voornaam) {

    this.voornaam = voornaam;
}

@NotNull(message = "{error.no.email}")
@Email(message = "{error.invalid.email}")
public String getEmail() {
    return email;
}

public void setEmail(String email) {
    this.email = email;
}

@NotNull(message = "{error.no.status}")
@Size(min = 1, message = "{error.no.valid.status}")
public String getStatus() {
    return status;
}

public void setStatus(String status) {

    this.status = status;
}

@NotNull(message = "{error.no.username}")
@Size(min = 2, message = "{error.invalid.usernamesize}")
public String getUsername() {
    return username;
}

public void setUsername(String username) {
    this.username = username;
}

public void setPassword(String password) {
       this.password = Password.getSaltedHash(password);
}

public boolean isPasswordCorrect(String password) {
    boolean result = false;
        result = Password.check(password, this.password);      
    return result;
}

@NotNull(message = "{error.no.password}")
@Size(min = 2, message = "{error.invalid.usernamesize}")
public String getPassword() {
    return this.password;
}



public void addPost(Post p) {
    if (p == null) {
        throw new DomainException("Post is null");
    }
    posts.add(p);
}

public void deletePost(Post p) {
    if (p == null) {
        throw new DomainException("Post is null");
    }
    posts.remove(p);
}

public Collection<Post> getPosts() {
    return posts;
}

@Override
public int hashCode() {
    int hash = 3;
    hash = 59 * hash + Objects.hashCode(this.username);
    return hash;
}

public void setHashedPassword(String password) {
    this.password = password;
}

}

The method that i'm currently using is:

   public void DeletePerson(String user) {
    entityManager.getTransaction().begin();
    entityManager.createQuery("delete from Person p where p.username=:username").setParameter("username", user).executeUpdate();
    entityManager.getTransaction().commit();
}

It gives the following error:

java.sql.SQLIntegrityConstraintViolationException: DELETE on table 'PERSON' caused a violation of foreign key constraint 'PRSNPRSNVRNDNSRNME' for key (vincent). The statement has been rolled back.

My guess is to add something to the manytomany annotation

create tables: https://i.stack.imgur.com/zS2Xf.png

UPDATE:

The code that i use now for deleting succesfully:

public void DeletePerson(String user) {
    entityManager.getTransaction().begin();
    entityManager.createNativeQuery("delete from PERSON_PERSON p where p.PERSON_USERNAME=?username or p.VRIENDEN_USERNAME=?username").setParameter("username", user).executeUpdate();
    entityManager.flush();
    Person tempPerson = getPerson(user);
    entityManager.remove(tempPerson);
    entityManager.getTransaction().commit();

}

but now i still retrieve old references although the data is deleted in the tables. I retrieve that data with:

entityManager.find(Person.class, user);
VincentN
  • 45
  • 1
  • 10
  • 1
    Leave JPA out of it for a bit and think about the SQL. You have to manage the keys in the association table before you can remove the Person rows. What does your schema look like? What does the SQL that is generated for you look like? – duffymo May 12 '17 at 11:02
  • just added an image of the generated tables @duffymo – VincentN May 12 '17 at 11:12
  • That's a start. Now look at the SQL JPA generates for you. You have to remove all the rows in the many-to-many table that have the Person you want to remove as friend before you try to remove the Person row. Should be a single unit of work. – duffymo May 12 '17 at 11:14
  • Look at the `deleteFriend(Person a, Person b)`. That is what you need to do, for all the friends that the person has, before deleting the person. Either by looping, or by doing the same thing using a native query that removes all references to the person to delete from the join table. – JB Nizet May 12 '17 at 11:17
  • I had tried deleting the PERSON_PERSON rows with a normal query but obviously that didn't work. But doing it with a native query fixed it thanks. – VincentN May 12 '17 at 11:29
  • after I deleted the object succesfully ( i checked the data manually in the db) , I can still retrieve the deleted object for some reason, any idea? @JBNizet – VincentN May 12 '17 at 11:59
  • You're probably not closing your entity manager. Or you deleted the person using a native query, but didn't clear the EM. – JB Nizet May 12 '17 at 12:02
  • tried to flush/ refresh/clear and close @JBNizet – VincentN May 12 '17 at 12:20
  • You have references to the removed person in your object model still. JPA provides caching options, so if you ever wish to take advantage of the performance benefits, your native SQL query isn't going to allow you to. You should look up any Person that references the person and remove the reference. Ie "select p from Person P join p.vrienden friend where friend.username = :username". Then you iterate over the list and remove the references before calling em.remove(person) so that JPA is aware of the changes as well as changing the relationship table – Chris May 12 '17 at 20:53

2 Answers2

0

You need to First Delete all Posts and vrienden (Relation - Maybe some intermediate table) then remove current Person (Because Foreign Key Constraint will not allow you to do this - As many other rows from different table may depend on this table.

https://stackoverflow.com/a/1089008/5284920

Community
  • 1
  • 1
Mohsin Mansoor
  • 155
  • 1
  • 1
  • 8
0

You cannot delete person that exists as friend in list of another person. First you should remove it from all friend lists (vrienden) in other person objects (rows in db) and than remove it. Error message clearly says that you cannot delete row because that record is FK in other table.

nick79
  • 417
  • 3
  • 7
  • after I deleted the object succesfully ( i checked the data manually in the db) , I can still retrieve the deleted object for some reason, any idea? @nick79 – VincentN May 12 '17 at 11:52
  • Hmm... strange... Are you sure? Is it possible that you saved instance in for example local variable or you can using EntityManager retrieve again that object? – nick79 May 12 '17 at 12:49
  • What happend if you try to delete object something like this: Person toBeDeleted = entityManager.findByUsername(user) entityManager.remove(toBeDeleted) – nick79 May 12 '17 at 12:52
  • I just updated the code how I do it now (check post). – VincentN May 12 '17 at 12:58
  • OK maybe EM cached that object. Try to call clear() method which will cause that all managed objects will become detached. EntityManager.clear(); – nick79 May 12 '17 at 13:08
  • Try like this: entityManager.getTransaction().begin(); entityManager.createNativeQuery("delete from PERSON_PERSON p where p.PERSON_USERNAME=?username or p.VRIENDEN_USERNAME=?username").setParameter("username", user).executeUpdate(); Person tempPerson = getPerson(user); entityManager.remove(entityManager.merge(tempPerson)); entityManager.getTransaction().commit(); entityManager.close(); – nick79 May 12 '17 at 13:48