Пару вещей. Используйте отладчик. Извините за снисходительность, но вы всегда должны знать, что делает ваше приложение. Вдоль этих строк включите вывод SQL, например, spring.jpa.show-sql=true
.
1 Не создавайте экземпляр Collection
в своем классе сущности. Это свойство предназначено для результатов запроса. Если вы хотите записать отношение, создайте набор или запросите существующий набор. Удалите new HashSet<Ads>()
в своем коде, и вы получите ужасный LazyInitializationExcetion
, который является вашей подсказкой для части 2.
private Set<Ads> adsFavourites;
2 Отношения не создаются в запросах по умолчанию Repository
или в по крайней мере, для отношений ManyToMany
. Вам нужно сделать свой собственный запрос, чтобы специально их прочитать.
@Query("from JwtUser u left join fetch u.adsFavourites where u.id=:id")
JwtUser findByIdJoinAds(@Param("id") Long id);
3 В spring-data-jpa объект отключается после запроса, хотя, по общему признанию, я немного не уверен в этом. Мне нужно было сделать save
после изменения набора adsFavourites
. Вероятно, потому что ManyToMany
отношениям нужна таблица соединений.
@Override
public void run(String... args) throws Exception {
write();
read();
delete();
read();
}
@Autowired
JwtUserRepository jwtRepository;
@Autowired
AdsRepository adsRepository;
private void delete() {
System.out.println("delete");
JwtUser jwtUser = jwtRepository.findByIdJoinAds(1L);
for (Ads ads : jwtUser.getAdsFavourites()) {
if (ads.getId().equals(1L)) {
jwtUser.getAdsFavourites().remove(ads);
break;
}
}
jwtRepository.save(jwtUser);
}
private void read() {
System.out.println("read");
System.out.println( jwtRepository.findByIdJoinAds(1L) );
}
private void write() {
System.out.println("write");
JwtUser user = new JwtUser();
Ads ads1 = new Ads();
adsRepository.save(ads1);
Ads ads2 = new Ads();
adsRepository.save(ads2);
Set<Ads> ads = new HashSet<>();
ads.add(ads1);
ads.add(ads2);
user.setAdsFavourites(ads);
jwtRepository.save(user);
}
Что дает мне:
Hibernate: drop table if exists ads CASCADE
Hibernate: drop table if exists jwt_user CASCADE
Hibernate: drop table if exists user_ads CASCADE
Hibernate: create table ads (id bigint generated by default as identity, primary key (id))
Hibernate: create table jwt_user (id bigint generated by default as identity, primary key (id))
Hibernate: create table user_ads (user_id bigint not null, ads_id bigint not null, primary key (user_id, ads_id))
Hibernate: alter table user_ads add constraint FKjo0u9wqmq7jkp7ovwxg5pebec foreign key (ads_id) references ads
Hibernate: alter table user_ads add constraint FK2tmldht7773rpej1o6nfyfmr foreign key (user_id) references jwt_user
2020-06-20 22:45:37.451 INFO 3048 --- [ task-1] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
2020-06-20 22:45:37.457 INFO 3048 --- [ task-1] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2020-06-20 22:45:37.629 INFO 3048 --- [ main] DeferredRepositoryInitializationListener : Spring Data repositories initialized!
2020-06-20 22:45:37.634 INFO 3048 --- [ main] c.m.ManytomanytestApplication : Started ManytomanytestApplication in 1.704 seconds (JVM running for 2.136)
write
Hibernate: insert into ads (id) values (null)
Hibernate: insert into ads (id) values (null)
Hibernate: insert into jwt_user (id) values (null)
Hibernate: insert into user_ads (user_id, ads_id) values (?, ?)
Hibernate: insert into user_ads (user_id, ads_id) values (?, ?)
read
Hibernate: select jwtuser0_.id as id1_1_0_, ads2_.id as id1_0_1_, adsfavouri1_.user_id as user_id1_2_0__, adsfavouri1_.ads_id as ads_id2_2_0__ from jwt_user jwtuser0_ left outer join user_ads adsfavouri1_ on jwtuser0_.id=adsfavouri1_.user_id left outer join ads ads2_ on adsfavouri1_.ads_id=ads2_.id where jwtuser0_.id=?
JwtUser(id=1, adsFavourites=[Ads(id=1), Ads(id=2)])
delete
Hibernate: select jwtuser0_.id as id1_1_0_, ads2_.id as id1_0_1_, adsfavouri1_.user_id as user_id1_2_0__, adsfavouri1_.ads_id as ads_id2_2_0__ from jwt_user jwtuser0_ left outer join user_ads adsfavouri1_ on jwtuser0_.id=adsfavouri1_.user_id left outer join ads ads2_ on adsfavouri1_.ads_id=ads2_.id where jwtuser0_.id=?
Hibernate: select jwtuser0_.id as id1_1_0_ from jwt_user jwtuser0_ where jwtuser0_.id=?
Hibernate: select adsfavouri0_.user_id as user_id1_2_0_, adsfavouri0_.ads_id as ads_id2_2_0_, ads1_.id as id1_0_1_ from user_ads adsfavouri0_ inner join ads ads1_ on adsfavouri0_.ads_id=ads1_.id where adsfavouri0_.user_id=?
Hibernate: delete from user_ads where user_id=? and ads_id=?
read
Hibernate: select jwtuser0_.id as id1_1_0_, ads2_.id as id1_0_1_, adsfavouri1_.user_id as user_id1_2_0__, adsfavouri1_.ads_id as ads_id2_2_0__ from jwt_user jwtuser0_ left outer join user_ads adsfavouri1_ on jwtuser0_.id=adsfavouri1_.user_id left outer join ads ads2_ on adsfavouri1_.ads_id=ads2_.id where jwtuser0_.id=?
JwtUser(id=1, adsFavourites=[Ads(id=2)])
И не забывайте:
@Entity
@Data
@EqualsAndHashCode(of = "id")
@ToString(of = "id")
public class Ads {
...
}