简体   繁体   中英

JPA: Eclipselink does not persist bi-directional relationships in database

My domain model in my Java EE 6 application contains bi-directional relationships like the following:

@Entity
public  class Users implements PrimaryKeyHolder<String>, Serializable {
  @Id
  private String username;

  @ManyToMany(mappedBy= "users")
  private List<Category> categories;

  public List<Category> getCategories() {
    if (categories == null) {
        categories = new ArrayList<Category>();
    }
    return Collections.unmodifiableList(categories);
  }

  public void addCategory(Category category) {
    if (categories == null) {
        categories = new ArrayList<Category>();
    }

    categories.add(category);
    if (!category.getUsers().contains(this)) {
        category.addUser(this);
    }
  }

  public void removeCategory(Category category) {
    if (categories == null) {
        categories = new ArrayList<Category>();
    }

    categories.remove(category);
    if (category.getUsers().contains(this)) {
        category.removeUser(this);
    }
  }

  public void setCategories(Collection<Category> categories) {
    if (this.categories == null) {
        this.categories = new ArrayList<Category>();
    }

    for (Iterator<Category> it = this.categories.iterator(); it.hasNext();) {
        Category category = it.next();
        it.remove();
        if (category.getUsers().contains(this)) {
            category.removeUser(this);
        }
    }

    for (Category category : categories) {
        addCategory(category);
    }
  }
}

@Entity
public class Category implements PrimaryKeyHolder<Long>, Serializable {
  @Id
  private Long id;

  @ManyToMany
  private List<User> users;

  public List<User> getUsers() {
    if (users == null) {
        users = new ArrayList<User>();
    }
    return Collections.unmodifiableList(users);
  }

  protected void addUser(User user) {
    if (users == null) {
        users = new ArrayList<User>();
    }
    users.add(user);
  }

  protected void removeUser(User user) {
    if (users == null) {
        users = new ArrayList<User>();
    }
    users.remove(user);
  }
}

UPDATE : I added relationship management code. Relationships are only set on the user side, therefore, the add/remove methods are protected in the Categoriy class. I set the categories on the user via setCategories .

Eclipselink correctly generates a join table CATEGORY_USERS. However, it does not persist any information in it (it only caches the information). Eg when I execute a find operation on the entity manager (eg a user), it returns the complete object graph (including the category relationship). But when I look at the tables, information are not updated (even though the transactions are committed). I also inserted a flush operation in my code, without success. Basic information (like String, Integer, etc. columns) gets correctly persisted and updated. After turning the log level to FINE, I can see that no SQL statements are executed for the relationships and the join table, respectively. But I do see SQL statements for uni-directional relationships.

My datamodel is covered by extensive unit tests, which all pass successfully. I basically do the same operation as in the container, commit the transaction, reload the entities from the db and check if the relationships are correctly set, which they are (I'm using the in-memory derby database for testing).

My app server is Glassfish v3.1-b17.

Any help is appreciated. Thanks, Theo

Ensure you are setting both sides of the relationship. The specification requires that the application sets both sides of the relationship as there is no relationship maintenance in JPA.

After endless hours of trying I finally got to a solution: I simply changed the owning side of the relationship, ie I put the mappedBy attribute to the category entity like this:

@ManyToMany(mappedBy= "categories")
private List<User> users;

The explanation for this can be found here

Four points:

1.- When you have an error, it's more simple find solution isolating them in an example (Or unit test) that reproduces the error. In your case, you could do an example with more simple getter and setter (for example, removing unmodifiableList use and other innecesary methods for testing actually issue ).

2.- I advise you to use pojos for model , without any logic. So, remove logic from pojos.

3.- We are using eclipselink and we do not have problems persisting relations. So, it is more possible that error will be in your code.

4.- Test annoting relation with " cascade = javax.persistence.CascadeType.ALL "

Apology for my poor English :(

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM