Skip to content

refactor(entity): update fetch strategies to LAZY for improved reliability#122

Merged
balazs-szucs merged 2 commits into
grimmory-tools:developfrom
balazs-szucs:OSIV-2
Mar 23, 2026
Merged

refactor(entity): update fetch strategies to LAZY for improved reliability#122
balazs-szucs merged 2 commits into
grimmory-tools:developfrom
balazs-szucs:OSIV-2

Conversation

@balazs-szucs

@balazs-szucs balazs-szucs commented Mar 22, 2026

Copy link
Copy Markdown
Contributor

Description

Linked Issue: Fixes #

Changes

See: https://www.baeldung.com/spring-open-session-in-view

First pass at fixing some of the hibernate stuff.

  • Fixes N + 1 queries
  • Fixes some SOLID violations
  • Improves reliability, makes queries fail fast

Main change is obvious trying to optimize the queries.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added ability to update book metadata with controlled refresh options.
    • Enhanced reading progress tracking with automatic completion date management.
  • Performance Improvements

    • Optimized data loading across the application through eager-loading query strategies.
    • Improved query efficiency with batch processing and lazy-loading configurations.
  • Bug Fixes

    • Fixed shelf book count calculations to use actual database values.
    • Improved book file reassignment and attachment operations.
  • Chores

    • Standardized transaction handling across services.

@coderabbitai

coderabbitai Bot commented Mar 22, 2026

Copy link
Copy Markdown
Contributor

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3555cf85-e7f7-4282-a16b-73262e713201

📥 Commits

Reviewing files that changed from the base of the PR and between 126e2ab and c602165.

📒 Files selected for processing (111)
  • booklore-api/src/main/java/org/booklore/app/mapper/AppBookMapper.java
  • booklore-api/src/main/java/org/booklore/app/service/AppBookService.java
  • booklore-api/src/main/java/org/booklore/config/security/SecurityUtil.java
  • booklore-api/src/main/java/org/booklore/config/security/aspect/BookAccessAspect.java
  • booklore-api/src/main/java/org/booklore/config/security/filter/AbstractQueryParameterJwtFilter.java
  • booklore-api/src/main/java/org/booklore/config/security/filter/AudiobookStreamingJwtFilter.java
  • booklore-api/src/main/java/org/booklore/config/security/filter/EpubStreamingJwtFilter.java
  • booklore-api/src/main/java/org/booklore/config/security/filter/JwtAuthenticationFilter.java
  • booklore-api/src/main/java/org/booklore/config/security/filter/KoboAuthFilter.java
  • booklore-api/src/main/java/org/booklore/config/security/service/AuthenticationService.java
  • booklore-api/src/main/java/org/booklore/config/security/service/OpdsUserDetailsService.java
  • booklore-api/src/main/java/org/booklore/controller/MetadataController.java
  • booklore-api/src/main/java/org/booklore/mapper/ShelfMapper.java
  • booklore-api/src/main/java/org/booklore/model/entity/BookEntity.java
  • booklore-api/src/main/java/org/booklore/model/entity/BookFileEntity.java
  • booklore-api/src/main/java/org/booklore/model/entity/BookLoreUserEntity.java
  • booklore-api/src/main/java/org/booklore/model/entity/LibraryEntity.java
  • booklore-api/src/main/java/org/booklore/model/entity/OidcSessionEntity.java
  • booklore-api/src/main/java/org/booklore/model/entity/RefreshTokenEntity.java
  • booklore-api/src/main/java/org/booklore/model/entity/ShelfEntity.java
  • booklore-api/src/main/java/org/booklore/model/entity/UserBookFileProgressEntity.java
  • booklore-api/src/main/java/org/booklore/model/entity/UserBookProgressEntity.java
  • booklore-api/src/main/java/org/booklore/model/entity/UserPermissionsEntity.java
  • booklore-api/src/main/java/org/booklore/repository/AuthorRepository.java
  • booklore-api/src/main/java/org/booklore/repository/BookAdditionalFileRepository.java
  • booklore-api/src/main/java/org/booklore/repository/BookFileRepository.java
  • booklore-api/src/main/java/org/booklore/repository/BookRepository.java
  • booklore-api/src/main/java/org/booklore/repository/BookReviewRepository.java
  • booklore-api/src/main/java/org/booklore/repository/BookdropFileRepository.java
  • booklore-api/src/main/java/org/booklore/repository/ComicCharacterRepository.java
  • booklore-api/src/main/java/org/booklore/repository/ComicCreatorRepository.java
  • booklore-api/src/main/java/org/booklore/repository/ComicLocationRepository.java
  • booklore-api/src/main/java/org/booklore/repository/ComicTeamRepository.java
  • booklore-api/src/main/java/org/booklore/repository/EmailRecipientV2Repository.java
  • booklore-api/src/main/java/org/booklore/repository/KoboDeletedBookProgressRepository.java
  • booklore-api/src/main/java/org/booklore/repository/KoboSnapshotBookRepository.java
  • booklore-api/src/main/java/org/booklore/repository/LibraryRepository.java
  • booklore-api/src/main/java/org/booklore/repository/MetadataFetchJobRepository.java
  • booklore-api/src/main/java/org/booklore/repository/OpdsUserV2Repository.java
  • booklore-api/src/main/java/org/booklore/repository/ReadingSessionRepository.java
  • booklore-api/src/main/java/org/booklore/repository/ShelfRepository.java
  • booklore-api/src/main/java/org/booklore/repository/UserBookFileProgressRepository.java
  • booklore-api/src/main/java/org/booklore/repository/UserBookProgressRepository.java
  • booklore-api/src/main/java/org/booklore/repository/UserRepository.java
  • booklore-api/src/main/java/org/booklore/service/AuthorService.java
  • booklore-api/src/main/java/org/booklore/service/ReadingSessionService.java
  • booklore-api/src/main/java/org/booklore/service/ShelfService.java
  • booklore-api/src/main/java/org/booklore/service/appsettings/AppSettingService.java
  • booklore-api/src/main/java/org/booklore/service/book/BookCreatorService.java
  • booklore-api/src/main/java/org/booklore/service/book/BookDownloadService.java
  • booklore-api/src/main/java/org/booklore/service/book/BookFileAttachmentService.java
  • booklore-api/src/main/java/org/booklore/service/book/BookQueryService.java
  • booklore-api/src/main/java/org/booklore/service/book/BookReviewService.java
  • booklore-api/src/main/java/org/booklore/service/book/BookService.java
  • booklore-api/src/main/java/org/booklore/service/book/PhysicalBookService.java
  • booklore-api/src/main/java/org/booklore/service/bookdrop/BookDropService.java
  • booklore-api/src/main/java/org/booklore/service/email/EmailProviderV2Service.java
  • booklore-api/src/main/java/org/booklore/service/email/EmailRecipientV2Service.java
  • booklore-api/src/main/java/org/booklore/service/file/FileMoveService.java
  • booklore-api/src/main/java/org/booklore/service/fileprocessor/AudiobookProcessor.java
  • booklore-api/src/main/java/org/booklore/service/hardcover/HardcoverSyncService.java
  • booklore-api/src/main/java/org/booklore/service/hardcover/HardcoverSyncSettingsService.java
  • booklore-api/src/main/java/org/booklore/service/kobo/KoboAutoShelfService.java
  • booklore-api/src/main/java/org/booklore/service/kobo/KoboEntitlementService.java
  • booklore-api/src/main/java/org/booklore/service/komga/KomgaService.java
  • booklore-api/src/main/java/org/booklore/service/koreader/KoreaderService.java
  • booklore-api/src/main/java/org/booklore/service/koreader/KoreaderUserService.java
  • booklore-api/src/main/java/org/booklore/service/library/LibraryProcessingService.java
  • booklore-api/src/main/java/org/booklore/service/library/LibraryService.java
  • booklore-api/src/main/java/org/booklore/service/metadata/BookCoverService.java
  • booklore-api/src/main/java/org/booklore/service/metadata/BookMetadataService.java
  • booklore-api/src/main/java/org/booklore/service/metadata/BookMetadataUpdater.java
  • booklore-api/src/main/java/org/booklore/service/migration/AppMigrationService.java
  • booklore-api/src/main/java/org/booklore/service/oidc/OidcGroupMappingService.java
  • booklore-api/src/main/java/org/booklore/service/opds/MagicShelfBookService.java
  • booklore-api/src/main/java/org/booklore/service/opds/OpdsBookService.java
  • booklore-api/src/main/java/org/booklore/service/opds/OpdsUserV2Service.java
  • booklore-api/src/main/java/org/booklore/service/progress/ReadingProgressService.java
  • booklore-api/src/main/java/org/booklore/service/reader/AudioMetadataService.java
  • booklore-api/src/main/java/org/booklore/service/reader/CbxReaderService.java
  • booklore-api/src/main/java/org/booklore/service/reader/EpubReaderService.java
  • booklore-api/src/main/java/org/booklore/service/reader/PdfReaderService.java
  • booklore-api/src/main/java/org/booklore/service/recommender/BookRecommendationService.java
  • booklore-api/src/main/java/org/booklore/service/recommender/BookSimilarityService.java
  • booklore-api/src/main/java/org/booklore/service/recommender/BookVectorService.java
  • booklore-api/src/main/java/org/booklore/service/restriction/ContentRestrictionService.java
  • booklore-api/src/main/java/org/booklore/service/upload/FileUploadService.java
  • booklore-api/src/main/java/org/booklore/service/user/DefaultSettingInitializer.java
  • booklore-api/src/main/java/org/booklore/service/user/UserProvisioningService.java
  • booklore-api/src/main/java/org/booklore/service/user/UserService.java
  • booklore-api/src/main/java/org/booklore/service/watcher/BookFileTransactionalHandler.java
  • booklore-api/src/main/resources/application.yaml
  • booklore-api/src/test/java/org/booklore/service/BookReviewServiceTest.java
  • booklore-api/src/test/java/org/booklore/service/OpdsBookServiceTest.java
  • booklore-api/src/test/java/org/booklore/service/OpdsUserV2ServiceTest.java
  • booklore-api/src/test/java/org/booklore/service/book/BookFileAttachmentServiceTest.java
  • booklore-api/src/test/java/org/booklore/service/book/BookServiceTest.java
  • booklore-api/src/test/java/org/booklore/service/bookdrop/BookDropServiceTest.java
  • booklore-api/src/test/java/org/booklore/service/hardcover/HardcoverSyncServiceTest.java
  • booklore-api/src/test/java/org/booklore/service/hardcover/HardcoverSyncSettingsServiceTest.java
  • booklore-api/src/test/java/org/booklore/service/kobo/KoboAutoShelfServiceTest.java
  • booklore-api/src/test/java/org/booklore/service/komga/KomgaServiceTest.java
  • booklore-api/src/test/java/org/booklore/service/library/LibraryProcessingServiceRegressionTest.java
  • booklore-api/src/test/java/org/booklore/service/library/LibraryProcessingServiceTest.java
  • booklore-api/src/test/java/org/booklore/service/metadata/BookCoverServiceTest.java
  • booklore-api/src/test/java/org/booklore/service/metadata/BookMetadataServiceTest.java
  • booklore-api/src/test/java/org/booklore/service/oidc/OidcGroupMappingServiceTest.java
  • booklore-api/src/test/java/org/booklore/service/reader/CbxReaderServiceTest.java
  • booklore-api/src/test/java/org/booklore/service/reader/EpubReaderServiceTest.java
  • booklore-api/src/test/java/org/booklore/service/upload/FileUploadServiceTest.java
  • booklore-api/src/test/java/org/booklore/service/user/UserProvisioningServiceTest.java

📝 Walkthrough

Walkthrough

This pull request refactors JPA lazy loading strategies and transaction boundaries across the codebase. Entity relationships are changed from eager to lazy loading with batch size hints, new repository query methods with @EntityGraph are introduced for eager fetching when needed, service methods are annotated with Spring @Transactional, and tests are updated to match the new data access patterns. Configuration enables open-in-view and Hibernate statistics.

Changes

Cohort / File(s) Summary
Entity Fetch Strategy Updates
booklore-api/src/main/java/org/booklore/model/entity/BookEntity.java, BookFileEntity.java, BookLoreUserEntity.java, LibraryEntity.java, OidcSessionEntity.java, RefreshTokenEntity.java, ShelfEntity.java, UserBookFileProgressEntity.java, UserBookProgressEntity.java, UserPermissionsEntity.java
Changed relationships from eager to explicit lazy loading via @ManyToOne(fetch = FetchType.LAZY), @OneToOne(fetch = FetchType.LAZY). Added @BatchSize(size = 20) to collection associations. BookLoreUserEntity.libraries changed from List to Set. ShelfEntity added @Formula computed bookCount field.
Repository Query Methods
booklore-api/src/main/java/org/booklore/repository/BookRepository.java, UserRepository.java, ShelfRepository.java, LibraryRepository.java, OpdsUserV2Repository.java
Added new @EntityGraph-annotated query methods: findByIdWithMetadata, findByIdWithBookFiles, findAllForSummaryByIds, findByIdFull (BookRepository); findByIdWithDetails, findByIdWithSettings, findByIdWithLibraries, findByIdWithPermissions, findAllWithDetails, findByUsernameWithDetails (UserRepository); findByIdWithUser (ShelfRepository, OpdsUserV2Repository); findByIdWithBooks, findByIdWithPaths, findAllWithPaths (LibraryRepository).
Repository Query Modifications & New Methods
BookFileRepository.java, AuthorRepository.java, ComicCharacterRepository.java, ComicCreatorRepository.java, ComicLocationRepository.java, ComicTeamRepository.java, ReadingSessionRepository.java, UserBookFileProgressRepository.java
Added @Transactional to @Modifying methods. Introduced reassignFilesToBook, reassignFileToBookWithPath, findByIdWithBookAndLibraryPath (BookFileRepository). Converted native SQL queries to JPQL for orphan-deletion methods in comic-related repositories. Enhanced findByUserIdAndBookId with fetch joins.
Service Layer Transaction Boundaries
booklore-api/src/main/java/org/booklore/config/security/service/AuthenticationService.java, OpdsUserDetailsService.java, ShelfService.java, BookCreatorService.java, BookQueryService.java, BookReviewService.java, BookService.java, BookDropService.java, FileMoveService.java, AudiobookProcessor.java, KoboEntitlementService.java, KomgaService.java, BookRecommendationService.java, BookSimilarityService.java, BookVectorService.java, MagicShelfBookService.java, OpdsBookService.java, OpdsUserV2Service.java, KoreaderUserService.java, ContentRestrictionService.java
Added @Transactional at class or method level. Most are @Transactional(readOnly = true) for query methods, @Transactional for write methods. Switched import from jakarta.transaction.Transactional to org.springframework.transaction.annotation.Transactional across services.
Service Repository Method Updates
booklore-api/src/main/java/org/booklore/service/AppBookService.java, BookDownloadService.java, BookFileAttachmentService.java, BookReviewService.java, BookService.java, PhysicalBookService.java, BookDropService.java, HardcoverSyncService.java, HardcoverSyncSettingsService.java, KoboAutoShelfService.java, KomgaService.java, LibraryProcessingService.java, LibraryService.java, BookCoverService.java, BookMetadataService.java, CbxReaderService.java, EpubReaderService.java, PdfReaderService.java, FileUploadService.java, DefaultSettingInitializer.java, UserService.java
Updated service methods to use new eager-loading repository queries (findByIdWithBookFiles, findByIdWithMetadata, findByIdWithDetails, etc.) instead of findById. Added new method enrichBooksForSummary and validateAccessAndGetProgress updates in AppBookService. Changed library assignments from List to Set in UserProvisioningService and OidcGroupMappingService.
Mapper Updates
booklore-api/src/main/java/org/booklore/mapper/AppBookMapper.java, ShelfMapper.java
AppBookMapper.toShelfSummary now uses ShelfEntity.getBookCount() directly instead of computing from bookEntities.size(). ShelfMapper.toShelf changed bookCount mapping from expression-based calculation to direct field mapping.
Security & Filter Updates
booklore-api/src/main/java/org/booklore/config/security/SecurityUtil.java, BookAccessAspect.java, AbstractQueryParameterJwtFilter.java, AudiobookStreamingJwtFilter.java, EpubStreamingJwtFilter.java, JwtAuthenticationFilter.java, KoboAuthFilter.java
Updated to use new repository methods for user/shelf loading: findByIdWithUser (ShelfRepository), findByIdWithDetails (UserRepository), findByIdWithMetadata (BookRepository). Ensures related entities are available during security checks.
Service-Specific Logic Changes
booklore-api/src/main/java/org/booklore/service/BookCreatorService.java, ReadingProgressService.java, LibraryService.java, BookMetadataService.java, BookMetadataUpdater.java, AudioMetadataService.java, AuthorService.java, ReadingSessionService.java, KoreaderService.java
BookMetadataService added updateMetadata() method and AuditService dependency. ReadingProgressService added conditional status computation for read progress. LibraryService refactored scan scheduling to use transaction synchronization. AudioMetadataService restructured single-file and folder-based info building. KoreaderService added null-guard for progressFraction parameter.
Configuration & Properties
booklore-api/src/main/resources/application.yaml
Enabled spring.jpa.open-in-view: true. Added Hibernate statistics configuration via hibernate.generate_statistics and logging.level for session metrics.
Test Updates
booklore-api/src/test/java/org/booklore/service/*
Updated mocking across 20+ test files to stub new repository query methods (findByIdWithBookFiles, findByIdWithDetails, findByIdWithMetadata, etc.). Updated assertions in BookFileAttachmentServiceTest, BookCoverServiceTest, and others to verify calls to new bulk-operation repository methods. Changed library collection types from List to Set in test setup (OidcGroupMappingServiceTest, UserProvisioningServiceTest).
Metadata Controller
booklore-api/src/main/java/org/booklore/controller/MetadataController.java
Import reordering only; no functional changes to controller methods or behavior.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Controller
    participant Service
    participant SecFilter
    participant UserRepo
    participant BookRepo
    participant DB

    Client->>SecFilter: Request with JWT token
    SecFilter->>UserRepo: findByIdWithDetails(userId)
    UserRepo->>DB: SELECT user + settings/libraries/permissions
    DB-->>UserRepo: BookLoreUserEntity with relations
    UserRepo-->>SecFilter: Enriched user entity
    SecFilter->>SecFilter: Create BookLoreUser DTO
    SecFilter->>SecFilter: Set SecurityContext
    SecFilter-->>Client: Proceed to Controller

    Client->>Controller: API request (authenticated)
    Controller->>Service: Business logic call
    Service->>BookRepo: findByIdWithBookFiles(bookId)
    BookRepo->>DB: SELECT book + bookFiles
    DB-->>BookRepo: BookEntity with files
    BookRepo-->>Service: Enriched book entity
    Service->>Service: Process with available files
    Service-->>Controller: Response DTO
    Controller-->>Client: HTTP response
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~55 minutes

Suggested reviewers

  • imajes

Poem

🐰 With lazy ears perked up, we fetch with care,
Batch-sizing dreams through the database air,
EntityGraphs paint pictures so bright,
Transactions wrapped 'round each query's flight! ✨

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

# Conflicts:
#	booklore-api/src/main/java/org/booklore/service/kobo/KoboEntitlementService.java
@balazs-szucs balazs-szucs marked this pull request as ready for review March 23, 2026 11:46
@balazs-szucs balazs-szucs merged commit e63733f into grimmory-tools:develop Mar 23, 2026
7 of 8 checks passed
cdome pushed a commit to cdome/ollumi that referenced this pull request Mar 25, 2026
zachyale pushed a commit to zachyale/grimmory that referenced this pull request Apr 17, 2026
zachyale pushed a commit to zachyale/grimmory that referenced this pull request Apr 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant