2

我有以下 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 时,都会填充流派表中已经存在的流派,如下所示:

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

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

        audioTrackService.addAudioTrack(track);

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

我正进入(状态:

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

我如何告诉 Hibernate 不要尝试将已经存在的流派重新插入到Genres级联插入表中?

4

1 回答 1

3

如果该流派已经存在,您必须提供其 ID。

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

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

Hibernate 尝试插入相应的流派,因为您没有提供它的 id。

插入音轨时,hibernate 必须在 AudioTrackGenre 表中插入记录。Hibernate 必须知道流派的 id。否则 hibernate 认为它们是新的流派。

编辑:

您似乎正在按需添加流派(例如 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);
}
于 2012-12-02T10:36:12.780 回答