diff --git a/backend/src/main/java/org/raddatz/familienarchiv/document/DocumentRepository.java b/backend/src/main/java/org/raddatz/familienarchiv/document/DocumentRepository.java index e887eeb8..c28a8132 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/document/DocumentRepository.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/document/DocumentRepository.java @@ -50,9 +50,11 @@ public interface DocumentRepository extends JpaRepository, JpaSp // Prüft effizient, ob ein Dateiname schon existiert (gibt true/false zurück) boolean existsByOriginalFilename(String originalFilename); + // lazy – @BatchSize(50) fallback active; see ADR-022 @EntityGraph("Document.full") List findBySenderId(UUID senderId); + // lazy – @BatchSize(50) fallback active; see ADR-022 @EntityGraph("Document.full") List findByReceiversId(UUID receiverId); diff --git a/backend/src/main/java/org/raddatz/familienarchiv/person/Person.java b/backend/src/main/java/org/raddatz/familienarchiv/person/Person.java index c99a6f76..d2332519 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/person/Person.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/person/Person.java @@ -11,6 +11,7 @@ import java.util.ArrayList; import java.util.List; import java.util.UUID; +// prevents infinite recursion in JSON serialization; see ADR-022 for lazy-fetch context @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"}) @Entity @Table(name = "persons") diff --git a/backend/src/main/java/org/raddatz/familienarchiv/tag/Tag.java b/backend/src/main/java/org/raddatz/familienarchiv/tag/Tag.java index 8be07fdc..fc5974a6 100644 --- a/backend/src/main/java/org/raddatz/familienarchiv/tag/Tag.java +++ b/backend/src/main/java/org/raddatz/familienarchiv/tag/Tag.java @@ -7,6 +7,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.persistence.*; import lombok.*; +// prevents infinite recursion in JSON serialization; see ADR-022 for lazy-fetch context @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"}) @Entity @Data diff --git a/backend/src/test/java/org/raddatz/familienarchiv/document/DocumentLazyLoadingTest.java b/backend/src/test/java/org/raddatz/familienarchiv/document/DocumentLazyLoadingTest.java index 3db5caaa..bc33815f 100644 --- a/backend/src/test/java/org/raddatz/familienarchiv/document/DocumentLazyLoadingTest.java +++ b/backend/src/test/java/org/raddatz/familienarchiv/document/DocumentLazyLoadingTest.java @@ -28,6 +28,17 @@ import static org.assertj.core.api.Assertions.assertThatCode; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; +/** + * Verifies that lazy-loaded associations on {@link Document} are accessible after a service + * method returns — i.e. no {@link org.hibernate.LazyInitializationException} is thrown outside + * the Hibernate session that loaded the entity. + * + *

Known limitation: calling {@code getDocumentById} (or any other service method) from + * within an already-open transaction is not covered here. When an outer transaction is active, + * the service's own {@code @Transactional} merges into it and Hibernate keeps the same session + * open, so the lazy-init guard behaves differently than in a non-transactional caller. This is a + * known constraint of the test setup, not a bug in the production code. + */ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE) @ActiveProfiles("test") @Import(PostgresContainerConfig.class) @@ -100,6 +111,7 @@ class DocumentLazyLoadingTest { }).doesNotThrowAnyException(); results.forEach(d -> assertThat(d.getSender()).isNotNull()); results.forEach(d -> assertThat(d.getSender().getLastName()).isNotNull()); + results.forEach(d -> assertThat(d.getTags()).isNotEmpty()); } @Test