The way you described your entities, Hibernate will expect the following database structure:
oeuvre(idoeuvre, titre, isbn, parution)
magasine(idoeuvre, titre, isbn, parution, type)
livre(idoeuvre, titre, isbn, parution, idauteur)
This will lead to a lot of duplication, and is probably not what you want. Now, you did describe two possible solutions though, namely:
Defining one table called oeuvre
, where each field is present, for example:
oeuvre(idoeuvre, titre, isbn, parution, type, idauteur)
Definining separate tables for livre
and magasine
, for example:
oeuvre(idoeuvre, titre, isbn, parution)
magasine(idmagasine, idoeuvre, idauteur)
livre(idlivre, idoeuvre, idauteur)
Now, as you did mention, the first solution doesn't allow you to define a constraint, while the second one does. Basically, that means you provided your own answer, if you need a constraint, then you'll have to differentiate between the different types, and then you'll have to go for the second approach.
You could then define the following constraints:
- Each
magasine.idoeuvre
and livre.idoeuvre
should be unique (you could even use them as a primary key)
livre.idauteur
should be not null
However, in this case, you don't need any inheritance. Inheritance within Hibernate is usually only done if multiple tables have the same fields, while in this case you have three separate tables, and thus three separate entities, no inheritance involved:
@Entity
public class Oeuvre {
@Id
@GeneratedValue(generator="system-uuid")
@GenericGenerator(name="system-uuid", strategy = "uuid")
private String idoeuvre;
@NotNull
private String titre;
@NotNull
private String ISBN;
@ColumnDefault("CURRENT_DATE()")
private LocalDate parution;
}
@Entity
public class Magasine { // No extends
@Id
@GeneratedValue(generator="system-uuid")
@GenericGenerator(name="system-uuid", strategy = "uuid")
private String idmagasine;
@OneToOne
@JoinColumn(name = "idoeuvre")
private Oeuvre oeuvre;
@Enumerated(EnumType.STRING)
private Type type;
}
@Entity
public class Livre { // No extends
@Id
@GeneratedValue(generator="system-uuid")
@GenericGenerator(name="system-uuid", strategy = "uuid")
private String idlivre;
@OneToOne
@JoinColumn(name = "idoeuvre")
private Oeuvre oeuvre;
@ManyToOne
@JoinColumn(name = "idauteur")
private Auteur auteur;
}
The only reason why you could use inheritance in this case is because both Magasine
and Livre
both have a similar Oeuvre
mapping, in that case, you could change your code like this:
@Entity
public class Oeuvre {
@Id
@GeneratedValue(generator="system-uuid")
@GenericGenerator(name="system-uuid", strategy = "uuid")
private String idoeuvre;
@NotNull
private String titre;
@NotNull
private String ISBN;
@ColumnDefault("CURRENT_DATE()")
private LocalDate parution;
}
@MappedSuperclass // No @Entity
public class SpecificOeuvre {
@OneToOne
@JoinColumn(name = "idoeuvre")
private Oeuvre oeuvre;
}
@Entity
public class Magasine extends SpecificOeuvre {
@Id
@GeneratedValue(generator="system-uuid")
@GenericGenerator(name="system-uuid", strategy = "uuid")
private String idmagasine;
@Enumerated(EnumType.STRING)
private Type type;
}
@Entity
public class Livre extends SpecificOeuvre {
@Id
@GeneratedValue(generator="system-uuid")
@GenericGenerator(name="system-uuid", strategy = "uuid")
private String idlivre;
@ManyToOne
@JoinColumn(name = "idauteur")
private Auteur auteur;
}
Both represent the same database structure, the only difference is that one of them has a separate class annotated with @MappedSuperclass
that contains all re-usable information between Magasine
and Livre
, which in this case is only the mapping to Oeuvre
.
If you want to know whether or not an Oeuvre
is linked to a Livre
or a Magasine
, you can use bi-directional mapping, for example:
@Entity
public class Oeuvre {
@Id
@GeneratedValue(generator="system-uuid")
@GenericGenerator(name="system-uuid", strategy = "uuid")
private String idoeuvre;
@NotNull
private String titre;
@NotNull
private String ISBN;
@ColumnDefault("CURRENT_DATE()")
private LocalDate parution;
@OneToOne(mappedBy = "oeuvre")
private Livre livre;
@OneToOne(mappedBy = "oeuvre")
private Magasine magasine;
}
Now you can see if oeuvre.getMagasine()
is given or oeuvre.getLivre()
is given.