Search code examples
javaspringspring-boothibernatehibernate-mapping

Use of @OneToMany or @ManyToMany targeting an unmapped class for List<String> in Spring data jpa


I am trying Spring data jpa implementation using CrudRepository. Below is my Entity Class

public class User {
  @Id
  @GeneratedValue(strategy=GenerationType.AUTO)
  private Long id = null;

  @OneToMany
  @ElementCollection
  @CollectionTable(name="photoUrls")
  @Valid
  private List<String> photoUrls = new ArrayList<String>();

  public Long getId() {
    return id;
  }

  public void setId(Long id) {
    this.id = id;
  }
  public List<String> getPhotoUrls() {
    return photoUrls;
  }

  public void setPhotoUrls(List<String> photoUrls) {
    this.photoUrls = photoUrls;
  }

}

And have a repository as below,

public interface UserRepository extends CrudRepository<User, Long>{
  
}

And trying to use h2 database for local testing

        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>

And from the CommandLineRunner calling the save method of the UserRepository, but getting below error,

Caused by: org.hibernate.AnnotationException: Use of @OneToMany or @ManyToMany targeting an unmapped class: model.User.photoUrls[java.lang.String] at org.hibernate.cfg.annotations.CollectionBinder.bindManyToManySecondPass(CollectionBinder.java:1191) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final] at org.hibernate.cfg.annotations.CollectionBinder.bindStarToManySecondPass(CollectionBinder.java:794) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]


Solution

  • Hibernate supports three data mapping types: basic (e.g String, int), Embeddable and Entity. Most often, a database row is mapped to an Entity, each database column being associated to a basic attribute. Embeddable types are more common when combining several field mappings into a reusable group (the Embeddable being merged into the owning Entity mapping structure).

    Both basic types and Embeddables can be associated to an Entity through the @ElementCollection, in a one-Entity-many-non-Entity relationship.

      @ElementCollection
      @CollectionTable(name="photoUrls",
                       joinColumns = @JoinColumn(name =  "user_id"))
      @Valid
      private List<String> photoUrls = new ArrayList<String>();
    

    So you need to remove @OneToMany as OneToMany is for one-Entity-many-Entity relationship. If you want to map to an Entity, then need change the code like below and create a new Entity Photo.

    @OneToMany(
            cascade = CascadeType.ALL,
            orphanRemoval = true
        )
    private List<Photo> photos = new ArrayList<>();
    

    In the above code , Photo is an Entity.

    see the below link for more information: https://vladmihalcea.com/how-to-optimize-unidirectional-collections-with-jpa-and-hibernate/