micronaut-projects / micronaut-projects/micronaut-data

@EntityGraph doesn't work in some cases.

Open
#960 2 comments 2 reactions 0 assignees View on GitHub
type: bug
Dominant language
Java
Stars
482
Forks
229
Avg merge
1d 7h
Merged PRs (30d)
32

Description

Hi,

It seems like `@EntityGraph` annotation is just ignored in some cases, especially for methods without arguments like `findAll()` or `list()` and also in a conjunction with spring `Specification`.
At the same time `@Join` works fine for `findAll()` with no arguments and doesn't work for `findAll(Specification spec)`.

### Task List

- [x] Steps to reproduce provided
- [ ] Stacktrace (if present) provided
- [ ] Example that reproduces the problem uploaded to Github
- [x] Full description of the issue provided (see below)

### Steps to Reproduce

1. Create two simple entities with `@ManyToOne` relation:
```
@Entity
@Table(name = "portal.book")
public class Book {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@NotNull
private String title;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "author_id")
private Author author;

}

@Entity
@Table(name = "portal.author")
public class Author {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@NotNull
private String name;

}

```
2. Define repository:
```
@Repository
@Transactional
public interface BookRepository extends CrudRepository {

@Override
@EntityGraph(attributePaths = {"author"})
List findAll();

// or

@EntityGraph(attributePaths = {"author"})
List listAll();

}

```

### Expected Behaviour

Author must be eagerly fetched according to the `@EntityGraph` annotation in order to avoid n+1 query:
```
DEBUG org.hibernate.SQL - select book0_.id as id1_3_0_, author1_.id as id1_2_1_, book0_.author_id as author_i3_3_0_, book0_.title as title2_3_0_, author1_.name as name2_2_1_ from portal.book book0_ inner join portal.author author1_ on book0_.author_id=author1_.id
```

### Actual Behaviour

Author is not eagerly fetched. Addition query is executed:
```
DEBUG org.hibernate.SQL - select book0_.id as id1_3_, book0_.author_id as author_i3_3_, book0_.title as title2_3_ from portal.book book0_

DEBUG org.hibernate.SQL - select author0_.id as id1_2_0_, author0_.name as name2_2_0_ from portal.author author0_ where author0_.id=?
```

### Environment Information

- **Micronaut Version:** 2.2.3
- **JDK Version:** 1.8

Some more test cases:

```
@Repository
@Transactional
public interface BookRepository extends CrudRepository {

@Override
@EntityGraph(attributePaths = {"author"})
List findAll();
// ^ X. Doesn't work. Causes n+1 additional query

@Override
@Join(value = "author", type = Join.Type.FETCH)
List findAll();
// ^ V. Works fine!

@EntityGraph(attributePaths = {"author"})
List findAll(Specification spec);
// ^ X. Doesn't work. Causes n+1 additional query

@Join(value = "author", type = Join.Type.FETCH)
List findAll(Specification spec);
// ^ X. Doesn't work. Causes n+1 additional query

@EntityGraph(attributePaths = {"author"})
Page findAll(Specification spec, io.micronaut.data.model.Pageable pageable);
// ^ X. Doesn't compile. Causes: Unable to implement Repository method: BookRepository.findAll(Specification spec, Pageable pageable). Cannot query entity [Book] on non-existent property: spec

@EntityGraph(attributePaths = {"author"})
Page findAll(Specification spec, org.springframework.data.domain.Pageable pageable);
// ^ X. Compiles but causes n+1 additional query

@Join(value = "author", type = Join.Type.FETCH)
Page findAll(Specification spec, org.springframework.data.domain.Pageable pageable);
// ^ X. Compiles but causes n+1 additional query

@EntityGraph(attributePaths = {"author"})
List findByTitle(String title);
// ^ V. Works fine in all cases when there is at least 1 input parameter!!!

}

```

Contributor guide

Open the contributing guide

Research direction

Start with the repository method handling for @EntityGraph, especially the BookRepository cases using findAll() and Specification, and reproduce the generated SQL described in the issue. Trace how no-argument and Specification methods are processed; done means the author relation is eagerly fetched without the reported n+1 queries and the pageable cases behave consistently.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, spring
Domain
backend, databases
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.