级联插入在休眠和级联表上的唯一约束

时间:2012-12-02 10:30:00

标签: java hibernate

我有以下SQL架构布局:

-- postgresql82+ syntax

create table AudioTracks (
  id serial primary key 
, name text
, size integer
, filePath text
, additionDate timestamp default now()
);

create table Genres (
  id serial primary key
, name text unique -- here is the unique constraint which troubles me 
, description text
, additionDate timestamp default now()
);

create table AudioTrackGenre (
  genreId integer references Genres (id) unique 
, audioTrackId integer references AudioTracks (id) unique 
, additionDate timestamp default now()
);

表格的两个相应映射:

@Entity(name = "AudioTracks")
public class AudioTrack implements Serializable {
    @Id
    @Column
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Column
    private String name;

    @Column
    private Integer size;

    @Column
    private String filePath;

    @Column
    @Temporal(TemporalType.TIMESTAMP)
    private Date additionDate;


    @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL )
    @JoinTable(name = "AudioTrackGenre",
            joinColumns =  { @JoinColumn(name = "audioTrackId") },
            inverseJoinColumns = { @JoinColumn(name = "genreId") }
    )
    @OrderBy("name")
    private Set<Genre> genres = new HashSet<Genre>();

    // setter/getter methods //
    ....
}

@Entity(name = "Genres")
public class Genre implements Serializable {
    @Id
    @Column
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Column
    private String name;

    @Column
    private String description;

    @Column
    @Temporal(TemporalType.TIMESTAMP)
    private Date additionDate;

    @ManyToMany(mappedBy = "genres")
    private Set<AudioTrack> audioTracks = new HashSet<AudioTrack>();

    public Genre() { }
    public Genre(String name) { this.name = name; }

    // setter/getter methods //
    ....
}

但是每当我试图保存AudioTrack时,填充Genres表中已经存在的Genres,就像这里一样:

        Set<Genre> genres = new HashSet<Genre>();
        genres.add(new Genre("ambient"));

        AudioTrack track = new AudioTrack();
        track.setGenres(genres);

        audioTrackService.addAudioTrack(track);

audioTrackService.addAudioTrack(track)事件在最低DAO级别sessionFactory.getCurrentSession().save(track)

我得到了:

ERROR: ERROR: duplicate key value violates unique constraint "genres_name_key"
  Detail: Key (name)=(ambient) already exists.

我如何告诉Hibernate不要尝试将现有类型重新插入到级联插入的Genres表中?

1 个答案:

答案 0 :(得分:3)

如果该类型已存在,则必须提供其ID。

请看这一行:new Genre("ambient")

hibernate怎么可能猜出Genre环境中现有的id是什么?

Hibernate尝试插入相应的类型,因为你没有提供它的id。

插入音轨时,hibernate必须在AudioTrackGenre表中插入记录。 Hibernate必须知道类型的ID。否则,休眠假设它们是新类型。

修改

您似乎在按需添加流派(如StackOverflow标记)。

您可以在代码中执行以下操作:

for (String genreName : submittedTextGenres) {
   Genre genre = genreDAO.findByName(genre);
   if (genre == null) { //a new genre
      genre = new Genre(genreName);
   }

   audioTrack.addGenre(genre);
}

如果您害怕并发用户添加相同类型:( JB Nizet建议)

for (String genreName : submittedTextGenres) {
   Genre genre = genreDAO.findByName(genre);
   if (genre == null) { //a new genre
      try {
         genre = genreDAO.insertGenre(genre); //a transaction
      } catch (GenreExistsException) {
         genre = genreDAO.findByName(genre); //a separate transaction
      }
   }

   audioTrack.addGenre(genre);
}