Skip to content

Instantly share code, notes, and snippets.

@vicly
Last active February 13, 2020 15:54
Show Gist options
  • Select an option

  • Save vicly/85d90acfd41b592eabf78ce7a4bcccc9 to your computer and use it in GitHub Desktop.

Select an option

Save vicly/85d90acfd41b592eabf78ce7a4bcccc9 to your computer and use it in GitHub Desktop.
[@ElementCollection lazy or eager] #JPA
public class Product {
  @Id
  private String id;

  @Column(name = "name", nullable = false)
  private String name;

  @ElementCollection(fetch = FetchType.LAZY) // 
  @CollectionTable(name = "product_price", joinColumns = @JoinColumn(name = "product_id"))
  private List<Money> prices = Lists.newArrayList();

  @ElementCollection(fetch = FetchType.EAGER)
  @CollectionTable(name = "product_plan", joinColumns = @JoinColumn(name = "product_id"))
  @Column(name = "plan_type_id")
  private Set<String> planTypeIds = Sets.newHashSet();

  @ElementCollection(fetch = FetchType.EAGER)
  @CollectionTable(name = "product_city_pair", joinColumns = @JoinColumn(name = "product_id"))
  private Set<CityPair> cityPairs = Sets.newHashSet();
}
  • EAGER => load product with SQL join, so you'll get many lines with duplicate id, name
  • LAZY => load product first, then using separate sql to load data
  • Why Set<CityPair> works? CityPair overwrites hashCode() and equals(), JPA/Hibernate actually populates duplicate records, while Java Set ensures DISTINCT
  • Why List<Money> does not work if using EAGER fetch?
    • we expect the price is unique per currency
    • List<Money> cannot handle "remove duplicate", thus we'll get duplicate elements after loading data
      • we use Property annotation rather than accessor annotation, we cannot manually handle it
    • we can fix it by using
      • LAZY (easiest will extra SQL execution)
      • use accessor annotation, and manually solve duplicate in setter
        • but we cannot distinguish loading data usecase and object modification usecase, so we cannot do input validation only for object modification usecase, e.g. throw IllegalArgumentException if duplicate currency found.
        • maybe we can use default setter for loading data usecase, and use customised method replacePrices(List<Money>) for object modification usecase.
      • or @PostLoad and EntityManager (@PostLoad does not work for Hibernate if using SessionFactory)
      • or write hibernate interceptor
      • or use Map<Currency, Money> (logically it should work, not verified)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment