2

In the context of a Spring Boot project using Spring Data JPA, I have defined the following entities:

  • Ent1 contains a list of Ent2 elements
  • Ent2 contains a list of Ent3 elements

When fetching a top-level Ent1 object through a repository, I'm seeing that every Ent2 which has more than one child appears multiple times in the Ent1.ent2 list. For example, an Ent2 with two childs will appear twice.

So instead of getting this:

enter image description here

I'm getting this:

enter image description here

Notes:

  • There are no duplicates in the database
  • If I delete ent3b in the database, the duplicated ent2 disappears

Here's a simplified version of the code:

```java
@Entity
public class Ent1 {
    @OneToMany(mappedBy="parent", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Ent2> ent2 = new ArrayList<Ent2>();    
}

@Entity
public class Ent2 {
    @ManyToOne
    @JoinColumn(name = "PARENT_ID", nullable = false)
    protected Ent1 parent;

    @OneToMany(mappedBy="parent", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Ent3> ent3 = new ArrayList<Ent3>();    
}

@Entity
public class Ent3 {
    @ManyToOne
    @JoinColumn(name = "PARENT_ID", nullable = false)
    protected Ent2 parent;
}

```
geschema
  • 2,464
  • 4
  • 30
  • 41
  • This is possibly result of using `@JoinColumn` along with `mappedBy` attribute of `@OneToMany`. You generally try to use either `@JoinColumn` or `mappedBy` depending upon uni/bi-directional relationship. Have a look at https://stackoverflow.com/questions/11938253/jpa-joincolumn-vs-mappedby to understand it more. – madteapot Apr 20 '21 at 11:26
  • @Setu thanks for the suggestion but that does not seem to solve the issue. – geschema Apr 20 '21 at 13:28
  • Are Ent1, 2 and 3 all persisting to the same table? If not, please clarify which tables. Perhaps also add the test-data you have in the tables so we can determine where the dupes are coming from. – Atmas Apr 21 '21 at 04:28
  • @Atmas each entity is persisted to a different table. I'm seeing no duplicates in the table itself, so they must be created by the ORM. – geschema Apr 21 '21 at 10:23
  • Can you try changing list to set? List had very specific connotation for ordering and is generally tn be avoided for jpa unless you're also persisting a column that resolved specific ordering. – Atmas Apr 21 '21 at 12:34
  • Can you add your test data as it exists in rows and also Id columns your entities are using? – Atmas Apr 21 '21 at 13:08
  • @Atmas yes changing list to set seems to solve the problem. Is that a true solution or just a workaround? The code used to work fine under EclipseLink (no duplicates in the list) but no so with Spring Data JPA/Hibernate. – geschema Apr 21 '21 at 16:12
  • I believe it's the true solution. If you look around there is a lot of verbiage out there on strange behavior of Lists which people tend to use as their Go To collection (myself included) but for JPA a list implies an ordering which requires an additional column so it becomes problematic to have the provider make assumptions on order when there is none for it to work with. Ill add an Answer to mark for posterity. – Atmas Apr 21 '21 at 18:02
  • Also for what it's worth it's more accurate to have it be a Set since there's no other way to discretely order it without additional information. Otherwise the provider has to opine on what order to put the elements into the object List or decide it doesn't care and secretly treat it as unordered (which is what a Set is by definition). I imagine EclipseLink must have used this style treatment. That's new informational for me so thanks for sharing that detail. I included that in the answer to help future readers. – Atmas Apr 21 '21 at 18:11

1 Answers1

3

Solution was to convert Lists into Sets. Lists in JPA require additional data (i.e. an ordering column) to extract a total ordering of elements from the relationship. It can be done but typically the average user only needs Set and it's a reflection of the relationship that most people model.

OP also commented that the previous provider didn't have this requirement so if you were previously using EclipseLink and switching ORM providers this may be a problem for you too.

Atmas
  • 2,389
  • 5
  • 13