简体   繁体   中英

List on object returned from database empty

I have three database tables that make up a many to many relationship. The tables are named Disposition, Disposition_Filter, and Dispositions_Disposition_Filter. Having mentioned that, Disposition_Disposition_Filter is the "join table".

The class DispositionFilterEntity looks like this:

@Getter
@Setter
@ToString
@EqualsAndHashCode
@NoArgsConstructor
@AllArgsConstructor
@Entity(name = "disposition_filter")
public class DispositionFilterEntity {
  @GenericGenerator(name = "uuid2", strategy = "org.hibernate.id.UUIDGenerator")
  @GeneratedValue(generator = "uuid2")
  @Id
  private String id;

  @Column private String name;
}

While the DispositionEntity class looks like this:

@Getter
@Setter
@ToString
@EqualsAndHashCode
@Entity(name = "dispositions")
public class DispositionEntity {
  @GenericGenerator(name = "uuid2", strategy = "org.hibernate.id.UUIDGenerator")
  @GeneratedValue(generator = "uuid2")
  @Id
  private String id;

  /** @see Disposition */
  @Column(nullable = false)
  private String name;

  @Column(nullable = false)
  private String description;

  @Column(nullable = false)
  private String category;

  @Column private boolean active;

  @Column private String label;

  @Column(name = "hidden_if_agent_not_assigned")
  private Boolean hidden;

  @Transient
  public Disposition getAttributeTypeEnum() {
    return Disposition.from(name);
  }

  @ManyToMany(fetch = FetchType.LAZY)
  @JoinTable(
    name = "dispositions_disposition_filter",
    joinColumns = {@JoinColumn(name = "filter_id")},
    inverseJoinColumns = {@JoinColumn(name = "disposition_id")})
  private List<DispositionFilterEntity> filters;
}

When I run my code in the debugger and make a request to retrieve all the disposition filter objects from the database, I can see that the filters member on the disposition object is coming back empty despite the fact that data actually DOES exist in that relationship. If anyone knows why that list is coming back empty and could point me in the correct direction, I would very much appreciate it.

As you realized in your second update, your first problem have to do with the way you configured the dispositions relationship in DispositionFilterEntity , you interchanged the name of the columns in the joinColumns and inverseJoinColumns attributes. Instead of this:

@ManyToMany
@JoinTable(
  name = "dispositions_disposition_filter",
  joinColumns = {@JoinColumn(name = "disposition_id")},
  inverseJoinColumns = {@JoinColumn(name = "filter_id")})
private List<DispositionEntity> dispositions;

You need:

@ManyToMany
@JoinTable(
  name = "dispositions_disposition_filter",
  joinColumns = {@JoinColumn(name = "filter_id")},
  inverseJoinColumns = {@JoinColumn(name = "disposition_id")})
private List<DispositionEntity> dispositions;

I think the fetch type is not relevant for the problem although it is always advisable to fetch collections lazily.

Now, you are facing a stack overflow error.

The cause of this error is that you are resolving both relationships at the same time, in a circular fashion.

I mean, say for instance, that you are fetching a DispositionFilterEntity from the database.

In your code you are resolving the relationship with dispositions , either explicitly, by invoking getDispositions in your code, or implicitly, by other means - we will see later that this is the case.

For every DispositionEntity fetched, you are resolving the relationship with filters , again, either explicitly, by invoking getFilters in your code, or implicitly, by other means.

As indicated in the different comments, the first stack overflow you got was caused by the implementation of the toString , and equals and hashCode of your entities. It is always a good practice to not include any relationship field in the implementation of these methods in an entity to avoid lazy initialization or other problems like the one that you are facing

As far as you are using Lombok, in order to prevent the error you need to annotate the dispositions field in DispositionFilterEntity with @ToString.Exclude and with @EqualsAndHashCode.Exclude .

In addition, you can also annotate in the same way the filters field in DispositionEntity .

Once this problem was resolved you faced a new stack overflow error. This time the error was caused by the logic you are using to convert your entities to DTOs.

You are using Mapstruct for that purpose.

First, the provided stack trace - although the source code you provided later does not include all the methods initially indicated - shows methods related with the conversion of different entity-DTOs pairs. I think it is always better to use one Mapper for every entity-DTO pair.

Back to the stack overflow error, one option you have to avoid it is to ignore one of the fields, either dispositions or filters , in the corresponding mapping method by providing the corresponding @Mapping annotation: which of them, it will depend on your actual use case.

It is important to annotate the right mapper method, in this case, the one that maps every entity to the corresponding DTO, not the contrary.

I initially advised you to take care of JSON serialization an apply @JsonIgnore or whatever you need prevent the error but probably, as you already have a DTO, it will be no longer required.

Of course, if you do not need the relationship to be bidirectional, one possible solution is to remove one side of the relation. The reason why the filters field is not providing you any result is because you again interchanged the values of the joinColumns and inverseJoinColumns . Instead of this:

@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(
  name = "dispositions_disposition_filter",
  joinColumns = {@JoinColumn(name = "filter_id")},
  inverseJoinColumns = {@JoinColumn(name = "disposition_id")})
private List<DispositionFilterEntity> filters;

You need:

@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(
  name = "dispositions_disposition_filter",
  joinColumns = {@JoinColumn(name = "disposition_id")},
  inverseJoinColumns = {@JoinColumn(name = "filter_id")})
private List<DispositionFilterEntity> filters;

Please, always remember that the inverseJoinColumns references the column to join with the entity applicable in the other side of the collection.

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