I'm trying use spring CRUDRepository for inserting new object into database using JPA database model (User.java, UserInfo.java). Database model are related with composite primary key (UserPK.java), where one of them is automatic generated (field named id) and second (field named type) is set in beginning.
And I get errors when I create new object with using CRUDRepository (UserRepository.java) - cannot insert new object into second model (UserInfo.java), because id is null (first model was added correctly). I think problem is in sharing/mapping composite primary key in database model. I tried the same model with EntityManager and it wasn't error - all was added. Next I used @PrimaryKeyJoinColumns annotation, but with that same result as above (but there I'm not sure that I used it correctly) - CRUDRepository failed and EntityManager success.
Can anyone help me find solution? I add also source code on GitHub if someone wants to run code.
Logs below:
Log CRUDRepository
Hibernate: select user0_.id as id1_0_1_, user0_.type as type2_0_1_, user0_.email as email3_0_1_, user0_.login as login4_0_1_, userinfo1_.id as id3_1_0_, userinfo1_.type as type4_1_0_, userinfo1_.name as name1_1_0_, userinfo1_.surname as surname2_1_0_ from user user0_ left outer join user_info userinfo1_ on user0_.id=userinfo1_.id and user0_.type=userinfo1_.type where user0_.id=? and user0_.type=?
Hibernate: call next value for seq_id
Hibernate: select userinfo0_.id as id3_1_0_, userinfo0_.type as type4_1_0_, userinfo0_.name as name1_1_0_, userinfo0_.surname as surname2_1_0_ from user_info userinfo0_ where userinfo0_.id=? and userinfo0_.type=?
Hibernate: insert into user (email, login, id, type) values (?, ?, ?, ?)
Hibernate: insert into user_info (name, surname, id, type) values (?, ?, ?, ?)
WARN 17653 --- [nio-8080-exec-3] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 23502, SQLState: 23502
ERROR 17653 --- [nio-8080-exec-3] o.h.engine.jdbc.spi.SqlExceptionHelper : NULL not allowed for column "ID"; SQL statement:
insert into user_info (name, surname, id, type) values (?, ?, ?, ?) [23502-196]
...
Log EntityManager
Hibernate: call next value for seq_id
Hibernate: insert into user (email, login, id, type) values (?, ?, ?, ?)
Hibernate: insert into user_info (name, surname, id, type) values (?, ?, ?, ?)
Code below:
Main model: User.java
import com.fasterxml.jackson.annotation.JsonManagedReference;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
@Entity
@Table(name = "USER")
@IdClass(UserPK.class)
public class User implements Serializable {
@OneToOne(cascade = CascadeType.ALL, mappedBy = "user")
@JsonManagedReference
private UserInfo info;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_ID")
@SequenceGenerator(name = "SEQ_ID", sequenceName = "SEQ_ID", allocationSize = 1)
@NotNull
@Column(name = "ID")
private Long id;
@Id
@NotNull
@Column(name = "TYPE")
private String type;
@NotNull
@Column(name = "LOGIN")
private String login;
@NotNull
@Column(name = "EMAIL")
private String email;
/* ... */
}
Second model: UserInfo.java
import com.fasterxml.jackson.annotation.JsonBackReference;
import javax.persistence.*;
import java.io.Serializable;
@Entity
@Table(name = "USER_INFO")
public class UserInfo implements Serializable {
@Id
@OneToOne(cascade = CascadeType.ALL)
@JoinColumns({
@JoinColumn(name = "id", referencedColumnName = "id"),
@JoinColumn(name = "type", referencedColumnName = "type")
})
@JsonBackReference
@MapsId
private User user;
@Column(name = "NAME")
private String name;
@Column(name = "SURNAME")
private String surname;
/* ... */
}
Composed primary key: UserPK.java
import java.io.Serializable;
public class UserPK implements Serializable {
private Long id;
private String type;
/* ... */
}
spring CRUDRepository: UserRepository.java
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface UserRepository extends CrudRepository<User, UserPK> {
User findByIdAndAndType(Long id, String type);
}
Repository using EntityManager: UserRepositoryEM.java
import org.springframework.stereotype.Repository;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.transaction.Transactional;
@Repository
@Transactional
public class UserRepositoryEM {
@PersistenceContext
private EntityManager entityManager;
public User findByKey(UserPK key) {
return entityManager.find(User.class, key);
}
public User save(User user) {
entityManager.persist(user);
entityManager.flush();
return user;
}
}
The
User
andUserPK
classes need slight modification. Your field to column mappings for the primary key should be inside theUserPK
class. Here are the changes,Corresponding changes to the repository,