spring-projects / spring-projects/spring-batch
Fetching Entities described via @EmbeddedId in Spring Batch and with JpaCursorItemReader returns always single value
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 3k
- Forks
- 2.5k
- Avg merge
- 6d 53m
- Merged PRs (30d)
- 3
Description
Bug description
Fetching Entities(UserRole in ManyToOne association) described via jakarta.persistence.EmbeddedId in Spring Batch and with JpaCursorItemReader returns always a single value.
Example: User has two UserRoles with roleId1=1 and roleId2=4. In ItemProcessor I get always either roleId1 or roleI2 but not both.
Environment
Spring boot 3.1.3, Spring Batch 5.0.3, Hibernate-Core 6.2.7
Entities
@Entity
@Table( name = "user"
})
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class User extends PersonExtendedImpl implements UserDetails, ToDto<UserDTO>, Serializable {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name = "User_ID")
private Integer id;
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@OneToMany(
mappedBy = "user",
cascade = CascadeType.ALL,
orphanRemoval = true)
private List<UserRole> userRoles = new ArrayList<UserRole>();
equals, hashcode, getter, setter
@Entity
@Table(name = "user_role",
uniqueConstraints={@UniqueConstraint(columnNames = {"User_ID", "Role_ID"})}
)
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class UserRole implements Serializable {
@EmbeddedId
private UserRoleKey id;
@Setter(AccessLevel.NONE)
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "User_ID", referencedColumnName = "User_ID", insertable=false, updatable=false)
private User user;
public UserRole(UserRoleKey id) {
this.id = id;
}
equals, hashcode, getter, setter
}
@Embeddable
public class UserRoleKey implements Serializable {
@Column(name = "User_ID")
private Integer userId;
@Column(name = "Role_ID")
private Integer roleId;
equals, hashcode, getter, setter
}
Steps to reproduce
@Bean
@Scope("prototype")
Step step( JobRepository jobRepository,
JpaCursorItemReader<User> userPrivilegeReader,
CustomerPrivilegeProcessor userPrivilegeProcessor,
PlatformTransactionManager userTransactionManager) throws Exception {
return new StepBuilder("customerPrivilegeStep", jobRepository)
.<User, User> chunk(10, userTransactionManager)
.reader( userPrivilegeReader )
.processor( userPrivilegeProcessor )
.writer(() -> System.out.println("NOT OKAY "))
.build();
}
This Step produces correct sql statement but just one UserRole fetched in List of userRoles.
SQL:
"""
SELECT u from User u
JOIN FETCH u.userRoles ur
WHERE u.expiresAt > CURRENT_TIMESTAMP
AND u.enabled = true
AND u.locked = false """
select u1_0.User_ID,u1_0.Auth_Type,u1_0.Birth_day,u1_0.Country_ID,u1_0.Email,u1_0.Enabled,u1_0.Expires_at,u1_0.First_Name,u1_0.Form_of_Address_ID,u1_0.Last_accessed_at,u1_0.Last_Name,u1_0.Last_updated_at,u1_0.Locked,u1_0.Locked_at,u1_0.Password,u1_0.Phone,u1_0.Registered_at,u1_0.Register_Type,u2_0.User_ID,u2_0.Role_ID,u1_0.Username
from user u1_0
join user_role u2_0 on u1_0.User_ID=u2_0.User_ID
where u1_0.Expires_at>current_timestamp(6)
and u1_0.Enabled=1 and u1_0.Locked=0
Important!
I could not reproduce the same issue in Spring Boot 3.1.3 and Spring MVC application environment!!!
Expected behavior
JpaItemReaders should fetch all associated Entities(UserRole's) into Collection of parent Entity(User).
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
The reproduction is centered on JpaCursorItemReader, the User/UserRole entities, and the JOIN FETCH query shown in the issue. Start by running the provided batch step and comparing its processor input with the SQL result, then trace reader and persistence behavior for the @EmbeddedId collection. Done means the reader supplies every associated UserRole for each User, matching the expected behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, spring
- Domain
- backend, database
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100