Я занимаюсь разработкой проекта Spring Boot (2.2.6.RELEASE) с использованием Hibernate ORM (5.4.x
)
Моя идея проста: я хочу создать зависимость типа @ManyToMany
, но с дополнительным столбцом (Двунаправленный).
Для этой проблемы я создал отдельный проект на github, чтобы другие люди, столкнувшиеся с этой проблемой, могли видеть, где они допустили ошибку.
Для этого Я использую Project Lombok аннотации.
Ссылка на GitHub : Github Project
Entity Реляционная диаграмма ссылка на изображение
Ошибка
org.springframework.orm.jpa.JpaSystemException: Could not set field value [SHORT_CIRCUIT_INDICATOR] value by reflection : [class com.user.manyToMany.entity.PostTagId.tagId]
setter of com.user.manyToMany.entity.PostTagId.tagId; nested exception is org.hibernate.PropertyAccessException: Could not set field value [SHORT_CIRCUIT_INDICATOR]
value by reflection : [class com.user.manyToMany.entity.PostTagId.tagId] setter of com.user.manyToMany.entity.PostTagId.tagId
Обновление 1:
Для записи, это решение работает на 100% если мы собираемся сделать это "однонаправленным".
Для этого просто исключите следующие строки:
Post. java
tag.getPosts().add(postTag);
postTag.getTag().getPosts().remove(postTag);
Tag. java
post.getTags().add(postTag);
postTag.getPost().getTags().remove(postTag);
Тест и код
В следующем разделе код и представлены тесты, которые не проходят код.
Тест, который не проходит
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class PostRepositoryTest {
@Autowired
private PostRepository postRepository;
@Autowired
private PostTagRepository postTagRepository;
@Autowired
private TagRepository tagRepository;
@BeforeEach
void setUp() {
postRepository.deleteAll();
postTagRepository.deleteAll();
tagRepository.deleteAll();
}
@Test
@Transactional
void saveMultiplePostToTag() {
Post post = new Post();
post.setTitle("Hibernate");
postRepository.save(post);
Post post2 = new Post();
post2.setTitle("High-Performance Java Persistence");
postRepository.save(post2);
Tag tag = new Tag();
tag.setId(100L);
tag.setName("business");
tag.addPost(postRepository.findByTitle("Hibernate"));
tag.addPost(postRepository.findByTitle("High-Performance Java Persistence"));
tagRepository.save(tag);
tag = tagRepository.findByName("business");
assertNotNull(tag,"checking if tag exists");
assertEquals("business", tag.getName(),"checking if name exists");
assertEquals(2, tag.getPosts().size(),"checking if middle table exists");
assertNotNull(tag.getPosts().get(0).getPost(),"checking if post exists");
assertNotNull(tag.getPosts().get(1).getPost(),"checking if post exists");
assertEquals("Hibernate",tag.getPosts().get(0).getPost().getTitle(),"checking if title correct");
}
}
Пост. @Entity
@Table
@Data
public class Tag {
@Id
@GeneratedValue
private Long id;
private String name;
@OneToMany(
mappedBy = "tag",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<PostTag> posts = new ArrayList<>();
public void addPost(Post post) {
PostTag postTag = new PostTag(post, this);
posts.add(postTag);
post.getTags().add(postTag);
}
public void removePost(Post post) {
for (Iterator<PostTag> iterator = posts.iterator();
iterator.hasNext(); ) {
PostTag postTag = iterator.next();
if (postTag.getPost().equals(post) && postTag.getTag().equals(this)) {
iterator.remove();
postTag.getPost().getTags().remove(postTag);
postTag.setPost(null);
postTag.setTag(null);
}
}
}
}
PostTag. java
@Entity
@Table
@Data
public class PostTag {
public PostTag() {}
public PostTag(Post post, Tag tag) {
this.post = post;
this.tag = tag;
this.id = new PostTagId(post.getId(), tag.getId());
}
@EmbeddedId
private PostTagId id;
@ManyToOne(fetch = FetchType.LAZY)
@MapsId("postId")
private Post post;
@ManyToOne(fetch = FetchType.LAZY)
@MapsId("tagId")
private Tag tag;
@Column
private String createdOn;
}
PostTagId. java
@Embeddable
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PostTagId implements Serializable {
private Long postId;
private Long tagId;
}