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()
);

そして、テーブルへの2つの対応するマッピング:

@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);

(最低のDAOレベルでaudioTrackService.addAudioTrack(track)動作します)sessionFactory.getCurrentSession().save(track)

私は得ています:

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

Genresカスケード挿入のテーブルに既存のジャンルを再挿入しないようにHibernateに指示するにはどうすればよいですか?

4

1 に答える 1

3

ジャンルがすでに存在する場合は、そのIDを指定する必要があります。

この行を見てください:new Genre("ambient")

休止状態は、ジャンルアンビエントの既存のIDが何であるかをどのように推測できますか?

IDを指定していないため、Hibernateは対応するジャンルを挿入しようとします。

オーディオトラックを挿入する場合、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);
}
于 2012-12-02T10:36:12.780 に答える