LppEdd
LppEdd

Reputation: 21134

JPA / Hibernate - Composite primary key with foreign key

I'm trying to develop a Spring Boot application using JPA and Hibernate, and I've got the following two tables:

CREATE TABLE IF NOT EXISTS `library`.`User` (
  `id` VARCHAR(30) NOT NULL COMMENT 'The username',
  `name` VARCHAR(50) NULL,
  `surname` VARCHAR(50) NULL,
  PRIMARY KEY (`id`))
ENGINE = InnoDB;

CREATE TABLE IF NOT EXISTS `library`.`Library` (
  `userId` VARCHAR(30) NOT NULL,
  `id` CHAR(36) NOT NULL COMMENT 'An autogenerated UUID',
  `name` VARCHAR(50) NULL,
  PRIMARY KEY (`id`, `userId`),
  INDEX `USER_idx` (`userId` ASC),
  CONSTRAINT `USER`
    FOREIGN KEY (`userId`)
    REFERENCES `library`.`User` (`id`)
    ON DELETE CASCADE
    ON UPDATE CASCADE)
ENGINE = InnoDB;

These two tables are mappes as follow: I use Lombok to avoid boring stuff. User:

@Entity
@Table(name = "user")
@NoArgsConstructor
@Getter
@Setter
public class User
{
   @Id
   @Column(name = "id")
   private String id;

   @Column(name = "name")
   private String name;

   @Column(name = "surname")
   private String surname;

   @OneToMany(mappedBy = "userId")
   private Set<Library> libraries = new HashSet<>();
}

Library:

@Entity
@Table(name = "library")
@IdClass(LibraryId.class)
@NoArgsConstructor
@Getter
@Setter
public class Library
{
   @Id
   @ManyToOne
   @JoinColumn(name = "userId", referencedColumnName = "id")
   private User userId;

   @Id
   @Column(name = "id")
   private String id;

   @Column(name = "name")
   private String name;
}

The composite Id for Library:

@RequiredArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@ToString
@EqualsAndHashCode
public class LibraryId implements Serializable
{
   @NonNull
   public String userId;

   @NonNull
   public String id;
}

I read everything here https://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing and still Spring/Hibernate returns this error when executing a query via Spring Repository findAll() method.

SQL Error: 1054, SQLState: 42S22
Unknown column 'libraries0_.user_id' in 'field list'

What's wrong? I lost a day and still I'm not understanding.

As per request, these are the two repositories:

@Repository
public interface UserRepository extends JpaRepository<User, String>
{
   //
}

@Repository
public interface LibraryRepository extends JpaRepository<Library, LibraryId>
{
   //
}

And the actual query:

select user0_.id as id1_1_, user0_.name as name2_1_, user0_.surname as surname3_1_ from user user0_

select libraries0_.user_id as user_id2_0_0_, libraries0_.id as id1_0_0_, libraries0_.id as id1_0_1_, libraries0_.user_id as user_id2_0_1_, libraries0_.name as name3_0_1_ from library libraries0_ where libraries0_.user_id=?

Seems like Hibernate is not doing a join...

And here is the Maven POM, as requested:

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

Upvotes: 2

Views: 3365

Answers (1)

LppEdd
LppEdd

Reputation: 21134

Ahhh finally the journey comes to an end... See this question
The problem is the Hibernate naming strategy when converting column names of entities.

Using:

spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

solved the problem. But I don't understand why @JoinColumn(name = "userId") is not recognized!

Upvotes: 1

Related Questions