Bael 7452 updated (#15714)
* BAEL-7452: Lazy loaded lists * BAEL-7452: Example with Lazy Lists * BAEL-7452: Test for lazy groups
This commit is contained in:
parent
69fad866d9
commit
15de11de9a
|
@ -0,0 +1,8 @@
|
|||
package com.baeldung.listvsset.eager.set.lazy.moderatedomain;
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class Application {
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package com.baeldung.listvsset.eager.set.lazy.moderatedomain;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.ManyToMany;
|
||||
import jakarta.persistence.Table;
|
||||
import java.util.Set;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Entity(name = "interest_group")
|
||||
@Table(name = "interest_group")
|
||||
public class Group {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
@ManyToMany
|
||||
private Set<User> members;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package com.baeldung.listvsset.eager.set.lazy.moderatedomain;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface GroupRepository extends JpaRepository<Group, Long> {
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package com.baeldung.listvsset.eager.set.lazy.moderatedomain;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class GroupService {
|
||||
|
||||
private final GroupRepository groupRepository;
|
||||
|
||||
@Autowired
|
||||
public GroupService(GroupRepository groupRepository) {
|
||||
this.groupRepository = groupRepository;
|
||||
}
|
||||
|
||||
public Optional<Group> findById(Long aLong) {
|
||||
return groupRepository.findById(aLong);
|
||||
}
|
||||
|
||||
public List<Group> findAll() {
|
||||
return groupRepository.findAll();
|
||||
}
|
||||
|
||||
public void save(Group group) {
|
||||
groupRepository.save(group);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package com.baeldung.listvsset.eager.set.lazy.moderatedomain;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonBackReference;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Lob;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import java.util.Objects;
|
||||
import lombok.Data;
|
||||
|
||||
@Entity
|
||||
@Data
|
||||
public class Post {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@Lob
|
||||
private String content;
|
||||
|
||||
@JsonBackReference
|
||||
@ManyToOne
|
||||
private User author;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Post post = (Post) o;
|
||||
|
||||
return Objects.equals(id, post.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return id != null ? id.hashCode() : 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package com.baeldung.listvsset.eager.set.lazy.moderatedomain;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface PostRepository extends JpaRepository<Post, Long> {
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package com.baeldung.listvsset.eager.set.lazy.moderatedomain;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonManagedReference;
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.Table;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Entity(name = "simple_user")
|
||||
@Table(name = "simple_user")
|
||||
public class User {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
private String username;
|
||||
private String email;
|
||||
|
||||
@JsonManagedReference
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "author")
|
||||
protected Set<Post> posts;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
User user = (User) o;
|
||||
|
||||
return Objects.equals(id, user.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return id != null ? id.hashCode() : 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package com.baeldung.listvsset.eager.set.lazy.moderatedomain;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface UserRepository extends JpaRepository<User, Long> {
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package com.baeldung.listvsset.eager.set.lazy.moderatedomain;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Transactional
|
||||
@Service
|
||||
public class UserService extends com.baeldung.listvsset.Service<User> {
|
||||
|
||||
public UserService(JpaRepository<User, Long> repository) {
|
||||
super(repository);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserRepository getRepository() {
|
||||
return ((UserRepository) super.getRepository());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package com.baeldung.listvsset.lazy.list.moderatedomain;
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class Application {
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package com.baeldung.listvsset.lazy.list.moderatedomain;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.ManyToMany;
|
||||
import jakarta.persistence.Table;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Entity(name = "interest_group")
|
||||
@Table(name = "interest_group")
|
||||
public class Group {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
@ManyToMany
|
||||
private List<User> members;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package com.baeldung.listvsset.lazy.list.moderatedomain;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface GroupRepository extends JpaRepository<Group, Long> {
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package com.baeldung.listvsset.lazy.list.moderatedomain;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.ToIntFunction;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
@Transactional
|
||||
public class GroupService {
|
||||
|
||||
private final GroupRepository groupRepository;
|
||||
|
||||
@Autowired
|
||||
public GroupService(GroupRepository groupRepository) {
|
||||
this.groupRepository = groupRepository;
|
||||
}
|
||||
|
||||
public Optional<Group> findById(Long aLong) {
|
||||
return groupRepository.findById(aLong);
|
||||
}
|
||||
|
||||
public List<Group> findAll() {
|
||||
return groupRepository.findAll();
|
||||
}
|
||||
public int countNumberOfRequestsWithFunction(ToIntFunction<List<Group>> function) {
|
||||
return function.applyAsInt(groupRepository.findAll());
|
||||
}
|
||||
|
||||
public <S extends Group> S save(S entity) {
|
||||
return groupRepository.save(entity);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package com.baeldung.listvsset.lazy.list.moderatedomain;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonBackReference;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Lob;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import lombok.Data;
|
||||
|
||||
@Entity
|
||||
@Data
|
||||
public class Post {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@Lob
|
||||
private String content;
|
||||
|
||||
@JsonBackReference
|
||||
@ManyToOne
|
||||
private User author;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package com.baeldung.listvsset.lazy.list.moderatedomain;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface PostRepository extends JpaRepository<Post, Long> {
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package com.baeldung.listvsset.lazy.list.moderatedomain;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonManagedReference;
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.Table;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Entity(name = "simple_user")
|
||||
@Table(name = "simple_user")
|
||||
public class User {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
private String username;
|
||||
private String email;
|
||||
|
||||
@JsonManagedReference
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "author")
|
||||
protected List<Post> posts;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
User user = (User) o;
|
||||
|
||||
return Objects.equals(id, user.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return id != null ? id.hashCode() : 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package com.baeldung.listvsset.lazy.list.moderatedomain;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface UserRepository extends JpaRepository<User, Long> {
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package com.baeldung.listvsset.lazy.list.moderatedomain;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Transactional
|
||||
@Service
|
||||
public class UserService extends com.baeldung.listvsset.Service<User> {
|
||||
|
||||
public UserService(JpaRepository<User, Long> repository) {
|
||||
super(repository);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserRepository getRepository() {
|
||||
return ((UserRepository) super.getRepository());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package com.baeldung.nplusone.defaultfetch.list;
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class Application {
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package com.baeldung.nplusone.defaultfetch.list;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonBackReference;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Lob;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
import lombok.Data;
|
||||
|
||||
@Entity
|
||||
@Data
|
||||
public class Post {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@Lob
|
||||
private String content;
|
||||
|
||||
@JsonBackReference
|
||||
@ManyToOne
|
||||
private User author;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package com.baeldung.nplusone.defaultfetch.list;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface PostRepository extends JpaRepository<Post, Long> {
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package com.baeldung.nplusone.defaultfetch.list;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonManagedReference;
|
||||
import jakarta.persistence.CascadeType;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.OneToMany;
|
||||
import jakarta.persistence.Table;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Entity(name = "simple_user")
|
||||
@Table(name = "simple_user")
|
||||
public class User {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
private String username;
|
||||
private String email;
|
||||
|
||||
@JsonManagedReference
|
||||
@OneToMany(cascade = CascadeType.ALL, mappedBy = "author")
|
||||
protected List<Post> posts;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package com.baeldung.nplusone.defaultfetch.list;
|
||||
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
@Lazy(value = false)
|
||||
public interface UserRepository extends JpaRepository<User, Long> {
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package com.baeldung.nplusone.defaultfetch.list;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Transactional
|
||||
@Service
|
||||
public class UserService extends com.baeldung.listvsset.Service<User> {
|
||||
|
||||
public UserService(JpaRepository<User, Long> repository) {
|
||||
super(repository);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserRepository getRepository() {
|
||||
return ((UserRepository) super.getRepository());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package com.baeldung.listvsset.lazy.list;
|
||||
|
||||
import static com.vladmihalcea.sql.SQLStatementCountValidator.assertSelectCount;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import com.baeldung.listvsset.BaseNPlusOneIntegrationTest;
|
||||
import com.baeldung.listvsset.lazy.list.moderatedomain.Application;
|
||||
import com.baeldung.listvsset.lazy.list.moderatedomain.Group;
|
||||
import com.baeldung.listvsset.lazy.list.moderatedomain.GroupService;
|
||||
import com.baeldung.listvsset.lazy.list.moderatedomain.User;
|
||||
import com.baeldung.listvsset.util.TestConfig;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
@SpringBootTest(classes = {Application.class, TestConfig.class}, properties = {
|
||||
"hibernate.show_sql=true",
|
||||
"logging.level.org.hibernate.SQL=debug",
|
||||
"logging.level.org.hibernate.orm.jdbc.bind=trace"
|
||||
})
|
||||
class NPlusOneLazyModerateDomainIntegrationTest extends BaseNPlusOneIntegrationTest<User> {
|
||||
|
||||
@Autowired
|
||||
private GroupService groupService;
|
||||
|
||||
@Test
|
||||
void givenLazyListBasedUser_whenFetchingAllUsers_thenIssueOneRequest() {
|
||||
getService().findAll();
|
||||
assertSelectCount(1);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(longs = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
|
||||
void givenLazyListBasedUser_whenFetchingOneUser_thenIssueOneRequest(Long id) {
|
||||
getService().getUserById(id);
|
||||
assertSelectCount(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenLazyListBasedGroup_whenFetchingAllGroups_thenIssueOneRequest() {
|
||||
groupService.findAll();
|
||||
assertSelectCount(1);
|
||||
}
|
||||
@Test
|
||||
void givenLazyListBasedGroup_whenFilteringGroups_thenIssueNPlusOneRequests() {
|
||||
int numberOfRequests = groupService.countNumberOfRequestsWithFunction(groups -> {
|
||||
groups.stream()
|
||||
.map(Group::getMembers)
|
||||
.flatMap(Collection::stream)
|
||||
.collect(Collectors.toSet());
|
||||
return groups.size();
|
||||
});
|
||||
assertSelectCount(numberOfRequests + 1);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(longs = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
|
||||
void givenLazyListBasedGroup_whenFetchingAllGroups_thenIssueOneRequest(Long groupId) {
|
||||
Optional<Group> group = groupService.findById(groupId);
|
||||
assertThat(group).isPresent();
|
||||
assertSelectCount(1);
|
||||
}
|
||||
|
||||
protected void addUsers() {
|
||||
List<User> users = jsonUtils.getUsers(User.class);
|
||||
databaseUtil.saveAll(users);
|
||||
List<Group> groups = jsonUtils.getGroupsWithMembers(Group.class);
|
||||
databaseUtil.saveAll(groups);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package com.baeldung.listvsset.lazy.list;
|
||||
|
||||
import static com.vladmihalcea.sql.SQLStatementCountValidator.assertSelectCount;
|
||||
|
||||
import com.baeldung.listvsset.BaseNPlusOneIntegrationTest;
|
||||
import com.baeldung.listvsset.util.TestConfig;
|
||||
import com.baeldung.nplusone.defaultfetch.list.Application;
|
||||
import com.baeldung.nplusone.defaultfetch.list.Post;
|
||||
import com.baeldung.nplusone.defaultfetch.list.User;
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
@SpringBootTest(classes = {Application.class, TestConfig.class}, properties = {
|
||||
"hibernate.show_sql=true",
|
||||
"logging.level.org.hibernate.SQL=debug",
|
||||
"logging.level.org.hibernate.orm.jdbc.bind=trace"
|
||||
})
|
||||
class NPlusOneLazySimpleDomainIntegrationTest extends BaseNPlusOneIntegrationTest<User> {
|
||||
|
||||
@Test
|
||||
void givenLazyListBasedUser_WhenFetchingAllUsers_ThenIssueOneRequests() {
|
||||
getService().findAll();
|
||||
assertSelectCount(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void givenLazyListBasedUser_WhenFetchingAllUsersCheckingPosts_ThenIssueNPlusOneRequests() {
|
||||
int numberOfRequests = getService().countNumberOfRequestsWithFunction(users -> {
|
||||
List<List<Post>> usersWithPosts
|
||||
= users.stream()
|
||||
.map(User::getPosts)
|
||||
.filter(List::isEmpty)
|
||||
.toList();
|
||||
return users.size();
|
||||
});
|
||||
assertSelectCount(numberOfRequests + 1);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(longs = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
|
||||
void givenLazyListBasedUser_WhenFetchingOneUser_ThenIssueTwoRequest(Long id) {
|
||||
getService().getUserByIdWithPredicate(id, user -> !user.getPosts().isEmpty());
|
||||
assertSelectCount(2);
|
||||
}
|
||||
|
||||
|
||||
protected void addUsers() {
|
||||
List<User> users = jsonUtils.getUsers(User.class);
|
||||
databaseUtil.saveAll(users);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue