BAEL-6320: added code support for the @NaturalId article

This commit is contained in:
emanuel.trandafir 2023-05-04 18:04:15 +02:00
parent 2d2c842d2f
commit 7be3725480
12 changed files with 316 additions and 1 deletions

View File

@ -0,0 +1,14 @@
package com.baeldung.spring.data.jpa.naturalid;
import com.baeldung.spring.data.jpa.naturalid.repository.NaturalIdRepositoryImpl;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(SpringBootApplication.class, args);
}
}

View File

@ -0,0 +1,35 @@
package com.baeldung.spring.data.jpa.naturalid;
import com.baeldung.spring.data.jpa.naturalid.entity.ConferenceRoom;
import com.baeldung.spring.data.jpa.naturalid.entity.GuestRoom;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import org.hibernate.Session;
import org.springframework.stereotype.Service;
import java.util.Optional;
@Service
public class HotelRoomsService {
private final EntityManager entityManager;
public HotelRoomsService(EntityManagerFactory entityManagerFactory) {
this.entityManager = entityManagerFactory.createEntityManager();
}
public Optional<ConferenceRoom> conferenceRoom(String name) {
Session session = entityManager.unwrap(Session.class);
return session.bySimpleNaturalId(ConferenceRoom.class)
.loadOptional(name);
}
public Optional<GuestRoom> guestRoom(int roomNumber, int floor) {
Session session = entityManager.unwrap(Session.class);
return session.byNaturalId(GuestRoom.class)
.using("roomNumber", roomNumber)
.using("floor", floor)
.loadOptional();
}
}

View File

@ -0,0 +1,10 @@
package com.baeldung.spring.data.jpa.naturalid;
import com.baeldung.spring.data.jpa.naturalid.repository.NaturalIdRepositoryImpl;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@Configuration
@EnableJpaRepositories(repositoryBaseClass = NaturalIdRepositoryImpl.class)
public class NaturalIdRepoConfig {
}

View File

@ -0,0 +1,56 @@
package com.baeldung.spring.data.jpa.naturalid.entity;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import org.hibernate.annotations.NaturalId;
@Entity
public class ConferenceRoom {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NaturalId(mutable = true)
private String name;
private int capacity;
public ConferenceRoom(String name, int capacity) {
this.name = name;
this.capacity = capacity;
}
protected ConferenceRoom() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public int getCapacity() {
return capacity;
}
public void setCapacity(int capacity) {
this.capacity = capacity;
}
@Override
public String toString() {
return "HotelRoom{" +
"id=" + id +
", name='" + name + '\'' +
", capacity=" + capacity +
'}';
}
}

View File

@ -0,0 +1,73 @@
package com.baeldung.spring.data.jpa.naturalid.entity;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import org.hibernate.annotations.NaturalId;
@Entity
public class GuestRoom {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NaturalId
private Integer roomNumber;
@NaturalId
private Integer floor;
private String name;
private int capacity;
public GuestRoom(int roomNumber, int floor, String name, int capacity) {
this.roomNumber = roomNumber;
this.floor = floor;
this.name = name;
this.capacity = capacity;
}
protected GuestRoom() {
}
public Long getId() {
return id;
}
public Integer getRoomNumber() {
return roomNumber;
}
public Integer getFloor() {
return floor;
}
public int getCapacity() {
return capacity;
}
public void setCapacity(int capacity) {
this.capacity = capacity;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "GuestRoom{" +
"id=" + id +
", roomNumber=" + roomNumber +
", floor=" + floor +
", name=" + name +
", capacity=" + capacity +
'}';
}
}

View File

@ -0,0 +1,9 @@
package com.baeldung.spring.data.jpa.naturalid.repository;
import com.baeldung.spring.data.jpa.naturalid.entity.ConferenceRoom;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface ConferenceRoomJpaRepo extends JpaRepository<ConferenceRoom, Long> {
}

View File

@ -0,0 +1,8 @@
package com.baeldung.spring.data.jpa.naturalid.repository;
import com.baeldung.spring.data.jpa.naturalid.entity.ConferenceRoom;
import org.springframework.stereotype.Repository;
@Repository
public interface ConferenceRoomRepository extends NaturalIdRepository<ConferenceRoom, String> {
}

View File

@ -0,0 +1,9 @@
package com.baeldung.spring.data.jpa.naturalid.repository;
import com.baeldung.spring.data.jpa.naturalid.entity.GuestRoom;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface GuestRoomJpaRepo extends JpaRepository<GuestRoom, Long> {
}

View File

@ -0,0 +1,11 @@
package com.baeldung.spring.data.jpa.naturalid.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.NoRepositoryBean;
import java.util.Optional;
@NoRepositoryBean
public interface NaturalIdRepository<T, ID> extends JpaRepository<T, ID> {
Optional<T> naturalId(ID naturalId);
}

View File

@ -0,0 +1,28 @@
package com.baeldung.spring.data.jpa.naturalid.repository;
import jakarta.persistence.EntityManager;
import org.hibernate.Session;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.transaction.annotation.Transactional;
import java.io.Serializable;
import java.util.Optional;
public class NaturalIdRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements NaturalIdRepository<T, ID> {
private final EntityManager entityManager;
public NaturalIdRepositoryImpl(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {
super(entityInformation, entityManager);
this.entityManager = entityManager;
}
@Override
public Optional<T> naturalId(ID naturalId) {
return entityManager.unwrap(Session.class)
.bySimpleNaturalId(this.getDomainClass())
.loadOptional(naturalId);
}
}

View File

@ -1 +1,2 @@
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE

View File

@ -0,0 +1,61 @@
package com.baeldung.spring.data.jpa.naturalid;
import com.baeldung.spring.data.jpa.naturalid.entity.ConferenceRoom;
import com.baeldung.spring.data.jpa.naturalid.entity.GuestRoom;
import com.baeldung.spring.data.jpa.naturalid.repository.ConferenceRoomJpaRepo;
import com.baeldung.spring.data.jpa.naturalid.repository.ConferenceRoomRepository;
import com.baeldung.spring.data.jpa.naturalid.repository.GuestRoomJpaRepo;
import jakarta.transaction.Transactional;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.Rollback;
import java.util.Optional;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest
class NaturalIdIntegrationTest {
@Autowired
private HotelRoomsService service;
@Autowired
private GuestRoomJpaRepo guestRoomJpaRepo;
@Autowired
private ConferenceRoomJpaRepo conferenceRoomJpaRepo;
@Autowired
private ConferenceRoomRepository conferenceRoomRepository;
@Test
void whenWeFindByNaturalKey_thenEntityIsReturnedCorrectly() {
guestRoomJpaRepo.save(new GuestRoom(23, 3, "B-423", 4));
Optional<GuestRoom> result = service.guestRoom(23, 3);
assertThat(result).isPresent()
.hasValueSatisfying(room -> "B-423".equals(room.getName()));
}
@Test
void whenWeFindBySimpleNaturalKey_thenEntityIsReturnedCorrectly() {
conferenceRoomJpaRepo.save(new ConferenceRoom("Colorado", 100));
Optional<ConferenceRoom> result = service.conferenceRoom("Colorado");
assertThat(result).isPresent()
.hasValueSatisfying(room -> "Colorado".equals(room.getName()));
}
@Test
void givenNaturalIdRepo_whenWeFindBySimpleNaturalKey_thenEntityIsReturnedCorrectly() {
conferenceRoomJpaRepo.save(new ConferenceRoom("Nevada", 200));
Optional<ConferenceRoom> result = conferenceRoomRepository.naturalId("Nevada");
assertThat(result).isPresent()
.hasValueSatisfying(room -> "Nevada".equals(room.getName()));
}
}