Один ко многим и повторяющаяся запись - PullRequest
0 голосов
/ 29 апреля 2011

Я использую JPA-> Hibernate.PlayFramework.Я хочу иметь отношения.

 Category - 1:n -> Tag

В каждой категории может быть много тегов, но теги об этом не знают.

Итак, я делаю так:

@Entity
public class Category ... {
    @OneToMany
    public List<Tag> tags = new LinkedList<Tag>();
}

У меня есть тест:

@ Test public void playWithTags () {

    Tag tag1 = new Tag("tag1").save(); // managed by playframework

    Category cat1 = new Category("cat1");
    cat1.tags.add(tag1);
    cat1.save();

    // check if tag1 and cat1 were saved  
    assertEquals(1, Tag.count());
    assertEquals(1, Category.count());

    Category cat2 = new Category("cat2");
    cat2.tags.add(tag1);
    cat2.save();

}

Результат:

16:18:01,555 ERROR ~ Duplicate entry '1' for key 'tags_id'
16:18:01,555 ERROR ~ Could not synchronize database state with session
org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96)
    at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelp
....
java:908)
    at java.lang.Thread.run(Thread.java:619)
Caused by: java.sql.BatchUpdateException: Duplicate entry '1' for key 'tags_id'
    at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:2020)

Кажется, что cat2.save ()попробуйте сделать больше, чем следует

Если при использовании merge () вместо save () все работает хорошо:

 cat2.merge();

НО ПОЧЕМУ?

Ответы [ 2 ]

6 голосов
/ 30 апреля 2011

Я исправил проблему. Проблема была в том, что я использовал НЕ ЭТО аннотация. Поэтому я просто изменил @OneToMany на @ManyToMany и вуаля - больше никаких ограничений нет.

Но если говорить об OneToMany, то, похоже, на уровне базы данных было однозначное ограничение, которое не позволило нам поместить неуникальные значения в tags_id. Поэтому мы не можем поместить один тег в одну категорию. То есть он хотел одну категорию для многих тегов, но если теги уже были «использованы» - ни за что .. Я пытался поместить unique = true / false в @JoinTable -> @JoinColumn - но это не помогает. Для меня это все еще странно, но, по крайней мере, текущая проблема была исправлена.

5 голосов
/ 29 апреля 2011

Вы смешиваете две концепции: первичный ключ и внешний ключ.

Может быть только один PK, но FK просто означает "должен быть элемент с этим идентификатором в некоторой другой таблице". ФК не ограничивает уникальность.

[ПРАВКА] Ваша проблема в том, что вы смешиваете сущности. Как вы получили tag1, который возвращается save()?

Эта сущность должна быть той, которую вы получаете из Hibernate, а не результат new. Даже если это выглядит безумно, вы должны сделать это в save():

session.save(tag);
return session.load(tag.getId());

Таким образом, вы получаете сущность, которой управляет Hibernate. Только когда объектом управляет Hibernate, Hibernate знает, когда ему нужно сохранить объект и когда он уже был сохранен.

Поэтому, когда вы делаете cat2.tags.add(tag1); в своем примере выше, Hibernate думает: «О, я ничего не знаю об этом теге, он должен быть новым».

И снова пытается сохранить метку.

...