Почему Hibernate не может инициализировать набор, хотя он содержится в графе сущностей и выполняется в активном сеансе? - PullRequest
0 голосов
/ 04 апреля 2019

В приложении я использую Spring Data JPA и Hibernate.У меня есть два класса Study и StudiesCategory.Эти два класса имеют двунаправленную ассоциацию @ManyToOne / @OneToMany.

В рамках транзакции, которую я изменяю, а затем извлекаю сущность Study.В рамках той же транзакции я получаю доступ к ассоциированному StudiesCategory и Set из Study s.

При вызове aStudy.getName() я получаю LazyInitializationException, который, я думаю, не должен быть брошен, потому чтоСессия все еще открыта.Мне кажется, что Hibernate не может каким-либо образом лениво инициализировать коллекцию.

Почему выдается исключение и как мне предотвратить это?

Я попытался установить fetch для ассоциации на EAGER, что решает проблему, но я не хочу этого делать и полагаться на графы сущностей.Глядя на SQL-запрос, который создает Hibernate, я не вижу проблем, его выполнение возвращает все, как и ожидалось.

Рассматриваемый метод:

    @Transactional
    public void addAndPrintStudy(Study study) {
        try {
            study = studyRepository.saveAndFlush(study);
        } catch (DataAccessException e) {
            throw new IllegalArgumentException("Study exists.");
        }

        Study study = studyRepository.findDeepByIdentifier(study.getIdentifier()).get();

        Set<Study> studies = study.getStudiesCategory().getStudies();

       for (Study aStudy : studies) {
         System.out.println(aStudy.getName());
       }
    }

Вот метод репозитория для извлечения сущности:

@PreAuthorize("permitAll()")
@EntityGraph("Study.studiesCategory.studies")
Optional<Study> findDeepByIdentifier(long identifier);

Вот два класса:

@Entity
@Table(name = "studies")
@NamedEntityGraphs({
                           @NamedEntityGraph(name = "Study.studiesCategory.studies",
                                             attributeNodes = @NamedAttributeNode(value = "studiesCategory", subgraph = "studiesCategory.studies"),
                                             subgraphs = @NamedSubgraph(name = "studiesCategory.studies", attributeNodes = @NamedAttributeNode("studies"))),
                           @NamedEntityGraph(name = "Study.studiesCategory",
                                             attributeNodes = @NamedAttributeNode("studiesCategory"))
                   })
public class Study extends ModelBase implements Serializable, Identifiable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "identifier")
    private long identifier;

    @Column(name = "name")
    @NotBlank
    private String name;

    @Column(name = "description")
    private String description;

    @ManyToOne(cascade = {CascadeType.DETACH, CascadeType.REFRESH})
    @JoinColumn(name = "studies_category_identifier", referencedColumnName = "identifier")
    @Valid
    @NotNull
    private StudiesCategory studiesCategory;

    @Column(name = "visible")
    private boolean visible;

    public Study() {
    }

    // getters and setters

    @Override
    public int hashCode() {
        return Objects.hash(name);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        Study study = (Study) o;
        return name.equals(study.name);
    }

    @Override
    public long getId() {
        return getIdentifier();
    }
}

@Entity
@Table(name = "studies_categories")
@NamedEntityGraphs(
        @NamedEntityGraph(
                name = "StudiesCategory.studies",
                attributeNodes = @NamedAttributeNode(value = "studies")
        )
)
public class StudiesCategory extends ModelBase implements Serializable, Identifiable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "identifier")
    private long identifier;

    @Column(name = "name")
    @NotBlank
    private String name;

    @Column(name = "description")
    private String description;

    @OneToMany(mappedBy = "studiesCategory", cascade = {CascadeType.DETACH, CascadeType.REFRESH})
    private Set<Study> studies;

    public StudiesCategory(){
    }

    // getters and setters

    @Override
    public long getId() {
        return getIdentifier();
    }

    @Override
    public int hashCode() {
        return Objects.hash(name);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        StudiesCategory that = (StudiesCategory) o;
        return name.equals(that.name);
    }
}
...