Persist ManyToMany сущности в H2 выдает исключение - PullRequest
0 голосов
/ 07 мая 2018

У меня есть 2 сущности, и у обоих есть списки друг друга.

Класс "Пост":

@ManyToMany(mappedBy = "posts", cascade=CascadeType.ALL)
private List<Tag> tags;

Класс "Метка":

@ManyToMany(cascade = CascadeType.ALL)
@JoinTable
private List<Post> posts;`

В БД у меня есть таблица "POSTS", таблица "TAGS" и "TAGS_POSTS" для отношений ManyToMany. Структура в базе данных и таблицы в БД в порядке. Но когда я начинаю настаивать, произошла ошибка.

Это код для добавления новой записи в базу данных, этот же код отлично работает для других объектов, даже для тега, который также имеет отношение ManyToMany.

private EntityManagerFactory emf;

@PersistenceUnit
public void setEmf(EntityManagerFactory emf) {
    this.emf = emf;
}

public Post add(Post post) {
    EntityManager em = emf.createEntityManager();
    em.getTransaction().begin();
    em.persist(post);
    em.getTransaction().commit();
    return post;
}

Теперь при запуске приложения я попытался заполнить БД некоторыми фиктивными данными для тестирования. Все остальные объекты с таким же кодом работали нормально, кроме Post.

Вот код (я пытался без установки атрибута тегов, с установкой его на пустой ArrayList, и с установкой его на список уже существующих тегов в db результат тот же):

 ApplicationContext ac =  SpringApplication.run(PostsPortalApplication.class, args);


 PostsService ps = (PostsService) ac.getBean("postsService");

 Post post = new Post();
 post.setId(j);
 post.setDate(new Date());
 post.setDescription("desc" +  "/" );
 post.setDislikes(5);
 post.setLikes(5);
 post.setLocationLat(5);
 post.setLocationLong(5);
 post.setPhotoUrl("URL" +  "/" + j);
 post.setTitle("Title"  + "/" + j);
 post.setUser(user);
 post.setTags(new ArrayList<>());
 ps.add(post);

Это сообщение об исключении (PostsService.java:38 is line): em.persist(post);

Исключение в потоке "main" javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: отдельная сущность передана в постоянное состояние: jovan.sf_62_2017.postsportal.pojo.Post в org.hibernate.internal.ExceptionConverterImpl.convert (ExceptionConverterImpl.java:149) в org.hibernate.internal.ExceptionConverterImpl.convert (ExceptionConverterImpl.java:157) в org.hibernate.internal.ExceptionConverterImpl.convert (ExceptionConverterImpl.java:164) в org.hibernate.internal.SessionImpl.firePersist (SessionImpl.java:789) в org.hibernate.internal.SessionImpl.persist (SessionImpl.java:767) at sun.reflect.NativeMethodAccessorImpl.invoke0 (собственный метод) at sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43) в java.lang.reflect.Method.invoke (Method.java:498) в org.springframework.orm.jpa.ExtendedEntityManagerCreator $ ExtendedEntityManagerInvocationHandler.invoke (ExtendedEntityManagerCreator.java:350) на com.sun.proxy. $ Proxy85.persist (неизвестный источник) в jovan.sf_62_2017.postsportal.services.implementations.PostsService.add (PostsService.java:38) at jovan.sf_62_2017.postsportal.PostsPortalApplication.main (PostsPortalApplication.java:67)

Вызвано: org.hibernate.PersistentObjectException: отсоединенная сущность передана в постоянное хранилище: jovan.sf_62_2017.postsportal.pojo.Post в org.hibernate.event.internal.DefaultPersistEventListener.onPersist (DefaultPersistEventListener.java:124) в org.hibernate.event.internal.DefaultPersistEventListener.onPersist (DefaultPersistEventListener.java:58) в org.hibernate.internal.SessionImpl.firePersist (SessionImpl.java:782) ... еще 9

Ответы [ 2 ]

0 голосов
/ 08 мая 2018

Прежде всего, пожалуйста, измените:

cascade=CascadeType.ALL

до:

cascade = {CascadeType.PERSIST, CascadeType.MERGE}

, поскольку CascadeType.REMOVE автоматически наследуется при использовании CascadeType.ALL, но удаление сущностей применяется не только к таблице ссылок, но и к другой стороне ассоциации. ( см. Слышать )

поэтому попробуйте этот код:

    @ManyToMany(mappedBy = "posts", 
            cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    private List<Tag> tags;




@ManyToMany(cascade = 
        {CascadeType.PERSIST, CascadeType.MERGE})
    @JoinTable(name = "post_tag",
        joinColumns = {
            @JoinColumn(
                name = "tag_id", 
                referencedColumnName = "id"
            )
        },
        inverseJoinColumns = {
            @JoinColumn(
                name = "post_id", 
                referencedColumnName = "id"
            )
        }
    )
private List<Post> posts;

но ваша проблема .... вы пытаетесь сохранить отдельный объект ((означает, что экземпляр этого объекта был сохранен в БД, но этот объект не находится в сеансе)) в БД с помощью методов persist:

 Post post = new Post();
 post.setId(j);
 .
 .
 .
 em.persist(post)

Метод persist предназначен для добавления экземпляра new entity (без установки идентификатора к нему) в контекст постоянства, то есть для перехода экземпляра из переходного состояния в постоянное состояние.

Обычно мы вызываем его, когда хотим вставить запись в базу данных (сохранить экземпляр сущности) так если ваш объект имеет переходное или постоянное состояние, вы можете использовать метод persist, но если ваш объект был отсоединен до того, как вы использовали метод слияния, чтобы сохранить его

0 голосов
/ 07 мая 2018

Вместо этого:

@ ManyToMany (cascade = CascadeType.ALL) @JoinTable приватный список сообщений ;

попробуйте следующее:

private List<Post> posts = new ArrayList<>();

@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(
    name = "posts_tags",
            joinColumns = { @JoinColumn(name = "fk_tags") },
            inverseJoinColumns = { @JoinColumn(name = "fk_posts") }
)
public List<Post> getPosts() {
    return posts;
}

public void setPosts(List<Post> posts) {
    this.posts = posts;
}

Здесь hibernate создаст промежуточную таблицу с именем (posts_tags) для сопоставления отношений «многие ко многим».

Теперь давайте упростим службу DAO:

@PersistenceContext(unitName = "myPersistenceUnit")
private EntityManager em;

@Transactional(value = "myTransactionManager",propagation = Propagation.REQUIRED)
public Post add(Post post) {
    em.persist(post);
    return post;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...