В приведенном ниже коде, если я не очищаю текущий сеанс, из метода возвращается только число девочек, даже если я хочу вернуть число всех детей этого родителя.
Хорошо видно, что У родителя с идентификатором 1 трое детей (2 девочки и 1 мальчик), но возвращаются только девочки из-за предыдущего метода получения, который возвращает родителей только с девочками. Когда я очищаю сеанс, чтобы избежать возврата из кэша, он возвращает 3, как и ожидалось. Кто-нибудь может помочь мне понять, почему это так и как я могу избежать этого, не очищая текущий сеанс?
@Service
public class ExampleServiceImpl implements ExampleService {
@Autowired
private ExampleRepository exampleRepository;
@Autowired
private SessionFactory sessionFactory;
@Override
@Transactional(readOnly = true)
public int getNumberOfChildren() {
List<Parent> parentList = exampleRepository.retrieveParentsWithGirls();
//sessionFactory.getCurrentSession().clear();
Parent parent = exampleRepository.retrieveParentWithId(1);
System.out.println(parent.getChildSet().size());
return parent.getChildSet().size();
}
}
Позвольте мне поделиться всем моим кодом, а также сценариями базы данных, чтобы сделать его более понятным.
Репозиторий:
@Repository
public class ExampleRepositoryImpl implements ExampleRepository {
@Autowired
private SessionFactory sessionFactory;
@Override
public List<Parent> retrieveParentsWithGirls() {
CriteriaBuilder builder = sessionFactory.getCriteriaBuilder();
CriteriaQuery<Parent> criteria = builder.createQuery(Parent.class);
Root<Parent> parentRoot = criteria.from(Parent.class);
Fetch<Parent, Child> fetchChildren = parentRoot.fetch("childSet", JoinType.LEFT);
Join<Parent, Child> joinChildren = (Join<Parent, Child>) fetchChildren;
criteria.where(builder.equal(joinChildren.get("sex"), "girl"));
criteria.distinct(true);
return sessionFactory.getCurrentSession().createQuery(criteria).getResultList();
}
@Override
public Parent retrieveParentWithId(int id) {
CriteriaBuilder builder = sessionFactory.getCriteriaBuilder();
CriteriaQuery<Parent> criteria = builder.createQuery(Parent.class);
Root<Parent> parentRoot = criteria.from(Parent.class);
parentRoot.fetch("childSet", JoinType.LEFT);
criteria.where(builder.equal(parentRoot.get("id"), id));
return sessionFactory.getCurrentSession().createQuery(criteria).getSingleResult();
}
}
Объекты:
@Entity
@Table(name = "child")
public class Child {
@Id
@Column(name = "id", unique = true, nullable = false)
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
@Column(name = "sex")
private String sex;
@JoinColumn(name = "parent_id", referencedColumnName = "id")
@ManyToOne(fetch = FetchType.LAZY)
private Parent parent;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Parent getParent() {
return parent;
}
public void setParent(Parent parent) {
this.parent = parent;
}
}
@Entity
@Table(name = "parent")
public class Parent {
@Id
@Column(name = "id", unique = true, nullable = false)
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "parent")
private Set<Child> childSet;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Set<Child> getChildSet() {
return childSet;
}
public void setChildSet(Set<Child> childSet) {
this.childSet = childSet;
}
}
Конфигурация базы данных:
@EnableTransactionManagement
@Configuration
@Conditional(DatabaseRequiredCondition.class)
public class DatabaseConfiguration {
@Value("${jdbc.driverClassName}")
private String DB_DRIVER;
@Value("${jdbc.pwd}")
private String DB_PASSWORD;
@Value("${jdbc.url}")
private String DB_URL;
@Value("${jdbc.username}")
private String DB_USERNAME;
@Value("${hibernate.dialect}")
private String HIBERNATE_DIALECT;
@Value("${hibernate.showSql}")
private String HIBERNATE_SHOW_SQL;
@Value("${hibernate.packagesScan}")
private String ENTITYMANAGER_PACKAGES_TO_SCAN;
@Value("${hibernate.tx_timeout}")
private Integer TIMEOUT_AS_SECONDS;
@Bean
@Primary
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(DB_DRIVER);
dataSource.setUrl(DB_URL);
dataSource.setUsername(DB_USERNAME);
dataSource.setPassword(DB_PASSWORD);
return dataSource;
}
@Bean
@Primary
public LocalSessionFactoryBean sessionFactory() throws IOException {
LocalSessionFactoryBean sessionFactoryBean = new LocalSessionFactoryBean();
sessionFactoryBean.setDataSource(dataSource());
sessionFactoryBean.setPackagesToScan(ENTITYMANAGER_PACKAGES_TO_SCAN);
Properties hibernateProperties = new Properties();
hibernateProperties.put("hibernate.dialect", HIBERNATE_DIALECT);
hibernateProperties.put("hibernate.show_sql", HIBERNATE_SHOW_SQL);
hibernateProperties.put("hibernate.format_sql", true);
sessionFactoryBean.setHibernateProperties(hibernateProperties);
return sessionFactoryBean;
}
@Bean(name="transactionManager")
@Primary
public HibernateTransactionManager transactionManager() throws IOException {
HibernateTransactionManager transactionManager =
new HibernateTransactionManager(sessionFactory().getObject());
transactionManager.setDefaultTimeout(TIMEOUT_AS_SECONDS);
return transactionManager;
}
}
Сценарии :
create table parent (id serial);
create table child (id serial, parent_id integer not null, sex character varying(10));
INSERT INTO public.parent values(default);
INSERT INTO public.parent values(default);
INSERT INTO public.child
(parent_id, sex)
VALUES(1, 'girl');
INSERT INTO public.child
(parent_id, sex)
VALUES(1, 'girl');
INSERT INTO public.child
(parent_id, sex)
VALUES(1, 'boy');
Сгенерированные сценарии Когда я запускаю код:
Hibernate:
select
parent0_.id as id1_23_0_,
childset1_.id as id1_5_1_,
childset1_.parent_id as parent_i3_5_1_,
childset1_.sex as sex2_5_1_,
childset1_.parent_id as parent_i3_5_0__,
childset1_.id as id1_5_0__
from
parent parent0_
left outer join
child childset1_
on parent0_.id=childset1_.parent_id
where
childset1_.sex=?
Hibernate:
select
parent0_.id as id1_23_0_,
childset1_.id as id1_5_1_,
childset1_.parent_id as parent_i3_5_1_,
childset1_.sex as sex2_5_1_,
childset1_.parent_id as parent_i3_5_0__,
childset1_.id as id1_5_0__
from
parent parent0_
left outer join
child childset1_
on parent0_.id=childset1_.parent_id
where
parent0_.id=1
Версия Hibernate: 5.4.5.Final