I have a following SQL schema layout:
-- 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()
);
And two corresponding mappings to tables:
@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 //
....
}
and
@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 //
....
}
But whenever i am trying to save AudioTrack, populated with Genres which are already exists in Genres table, like here:
Set<Genre> genres = new HashSet<Genre>();
genres.add(new Genre("ambient"));
AudioTrack track = new AudioTrack();
track.setGenres(genres);
audioTrackService.addAudioTrack(track);
(the audioTrackService.addAudioTrack(track)
thing does sessionFactory.getCurrentSession().save(track)
at lowest DAO level)
i am getting:
ERROR: ERROR: duplicate key value violates unique constraint "genres_name_key"
Detail: Key (name)=(ambient) already exists.
How do i tell Hibernate not to try to re-insert already existing genres to Genres
table on cascade inserts?
If the genre already exists, you must provide its id.
Look at this line: new Genre("ambient")
.
How could hibernate possibly guess what is the existing id of the Genre ambient?
Hibernate tries to insert the corresponding genre, because you haven't provided its id.
When you insert the audio track, hibernate must inserts records in the AudioTrackGenre table. Hibernate must know the ids of the genres. Otherwise hibernate assumes they are new genres.
Edit:
It seems you are adding genres on demand(like StackOverflow tags).
You can do the following in your code:
for (String genreName : submittedTextGenres) {
Genre genre = genreDAO.findByName(genre);
if (genre == null) { //a new genre
genre = new Genre(genreName);
}
audioTrack.addGenre(genre);
}
If you are afraid of a concurrent user adding the same genres: (suggestion by 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);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With