Как добавить дополнительный столбец в отношении @ManyToMany в Hibernate 5 - PullRequest
5 голосов
/ 26 апреля 2020

Я занимаюсь разработкой проекта 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;

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...