Spring Data / Hibernate игнорирует предложение where и возвращает кешированный объект - PullRequest
0 голосов
/ 06 января 2020

Так что вот немного контекста, у меня возникла ситуация, когда hibernate или spring-data игнорируют предложение where и возвращают кешированный объект, и я не могу найти почему.

Пример кода :

//The entities are mapped properly with standard getters, setters, equals and hashCodes.

public class Foo {

    private Long id;

    private Set<Bar> bars;

}

public class Bar {

    private Long id;

    private String name;

    private Boolean active;

}

public class FooRepository extends ... {

    @Query("FROM Foo f LEFT JOIN FETCH f.bars b WHERE f.id = :id AND b.active = true")
    Optional<Foo> findByIdWithActiveBars(Long id);

}

// problematic method
public Foo remove(Long id, names) {
    methodA(id, names);

    return fooRepository.findByIdWithActiveBars(id);
}

@Transactional(propagation= Propagation.SUPPORTS)
public void methodA(long id, Set<String> names) {
    final Optional<Foo> foo = fooRepository.findById(id);

    invalidateBars(foo, names);
}

private void invalidateBars(Foo foo, Set<String> names) {
    final Set<Bar> barsToUpdate = new HashSet<>();

    foo.getBars().stream()
        .filter(names.contains(bar.getName())
        .forEach(bar -> {
            bar.setActive(false)
            barsToUpdate.add(bar);
        );

    barRepository.saveAll(barsToUpdate);
}

Проблема с приведенным выше кодом заключается в том, что метод remove всегда возвращает объект foo со всеми барами it (включая те, которые имеют активное значение false), но если я прокомментирую вызов methodA, тогда результат fooRepository.findByIdWithActiveBars (id) будет таким, как и ожидалось (к объекту foo прикреплены только активные столбцы).

Сначала я подумал, что использование barRepository "разрушает" кэш из-за родительского объекта не обновлялся (даже несмотря на то, что коллекция bar находится в hashCode foo и равна, поэтому он должен отличаться), и объект, кэшированный первым findById, выполненным в методе methodA, был возвращен результат (все же это игнорировало бы предложение where) поэтому после небольшого копания на net я нашел исправление: добавьте

entityManager.clear();

в конце Methoda. Но я не удовлетворен, так как хочу знать причину этой проблемы. Я почти уверен, что это связано с кэшем первого уровня в Hibernate, но я не могу понять, почему.

Я был бы очень рад, если бы кто-то мог пролить мне свет на эту проблему.

...