This is an old revision of the document!
Table of Contents
Hibernate is the implementation of the Java Persistence API.
Annotations
Tutorials: http://viralpatel.net/blogs/hibernate-one-to-many-annotation-tutorial/
- One Department has many employees
- One Employee has one deparment
ACHTUNG:
- Bei OneToMany, ManyToOne bezieht sich der erste Teil auf die Klasse, in welcher die annotierte Variable befindet.
Wenn wir in der Klasse Department das Set employees annotieren - dann steht dort @OneToMany. Weil One Department Many employees hat.
@ManyToOne
Then the modelling will look as following:
@Entity
@Table(name="EMPLOYEE")
public class Employee {
@ManyToOne
@JoinColumn(name="department_id")
private Department department;
}
@Entity
@Table(name="DEPARTMENT")
public class Department{
@OneToMany(mappedBy="department")
private Set<Employee> employees;
}
Discriminators
Discriminators are used for for storing class hierarchies in a single table. If having RedCar.class inheriting from Car.class - both stored in one table, then discriminator tells - hwne t orestore a RedCar and when t orestore a Car.
The element is required for polymorphic persistence using the table-per-class-hierarchy mapping strategy and declares a discriminator column of the table. The discriminator column contains marker values that tell the persistence layer what subclass to instantiate for a particular row.
Spring
ManyToOne
The Domain Model looks as following
Campus -is-> Location CampusPart -is-> Location Campus -hasmany-> CampusPart
Introduce a Superclass with an ID.
@MappedSuperclass
@Table(name = "locations", schema = "public")
public abstract class ELocation {
@Id
@Column(name = "ID", unique = true, nullable = false, insertable = false, updatable = false)
protected UUID id = UuidCreator.getSequential();
}
Bidirectional Many-To-Many
Here Both Entities Campus and CampuPart have a Link on each other. This is called a BiDirectional modeling
- Owning-side vs. inverse-side https://www.baeldung.com/hibernate-one-to-many
Owning - with Join Table
Introduce an ECampusPart Here the JoinTable is on CampusPart, so it is the owning-side of the connection.
@Entity(name = "ECampusPart")
@Table(name = "campusparts", schema = "public")
public class ECampusPart extends ELocation {
/*
Modeling a bidirectional relationship here.
JoinTable means - that relationships will be extracted explicitely to an own table.
Allows to explicitely name the columns: campuspart_id and campus_id here
*/
@ManyToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
@JoinTable(
name = "campus_campuspart",
joinColumns = {@JoinColumn(name = "campuspart_id")},
inverseJoinColumns = {@JoinColumn(name = "campus_id")}
)
private ECampus campus;
Using “JoinTable” results in the creation of a special table
@Entity(name = "ECampusPart")
@Table(name = "campusparts", schema = "public")
public class ECampusPart extends ELocation {
@ManyToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
@JoinTable(
name = "campus_campuspart",
joinColumns = {@JoinColumn(name = "campuspart_id")},
inverseJoinColumns = {@JoinColumn(name = "campus_id")}
)
private ECampus campus;
Results in
campuses
| dtype | id | object_type | name |
|---|---|---|---|
| ECampusPart | 497ffe9a-51bb-4ab4-bc3d-b8923d620703 | CampusPart | ViennaSmart City Campus front part |
campusparts
| dtype | id | object_type | name |
|---|---|---|---|
| ECampus | dbadab87-7b6d-4e8b-b2c8-0663d68dfe7b | Campus | ViennaSmart City Campus |
campus_campuspart
| campus_id | campuspart_id |
|---|---|
| 497ffe9a-51bb-4ab4-bc3d-b8923d620703 | dbadab87-7b6d-4e8b-b2c8-0663d68dfe7b |
Owning-side - with embedded foreign key
Omitting the “JoinTable” results in embedding the Foreign key campus_id - into the CampusPart table
@Entity(name = "ECampusPart")
@Table(name = "campusparts", schema = "public")
public class ECampusPart extends ELocation {
@ManyToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
private ECampus campus;
Results in
campuses
| dtype | id | object_type | name | campus_id |
|---|---|---|---|---|
| ECampusPart | 497ffe9a-51bb-4ab4-bc3d-b8923d620703 | CampusPart | ViennaSmart City Campus front part | dbadab87-7b6d-4e8b-b2c8-0663d68dfe7b |
campusparts
| dtype | id | object_type | name |
|---|---|---|---|
| ECampus | dbadab87-7b6d-4e8b-b2c8-0663d68dfe7b | Campus | ViennaSmart City Campus |
Inverse-side
Introduce an ECampus. Here the mappedBy is on Campus, so it is the inverse-side of the connection.
@Entity(name="ECampus")
@Table(name = "campuses", schema = "public")
public class ECampus extends ELocation {
@OneToMany(mappedBy = "campus", cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
private Set<ECampusPart> campusParts = new HashSet<>();
}
Warning: bidirectional relationships
ManyToMany relationships can lead to inconsitancies when
- settings links back
- there are multiple entities linking, back to parents
- entities have inconsistant list of members
Transactional
Seems like when wiring entities, which are affected on both sides - it should happen in 1 transaction.
In Spring boot you need to annotate a method with @Transactional
https://thorben-janssen.com/transactions-spring-data-jpa/
@Service
@Getter
public class EquipmentService {
@Autowired
private EquipmentRepository equipmentRepository;
@Transactional
public void updateEquipmentFeeds(ResourcePK equipmentFeeds, ResourcePK equipmentTarget) {
Assert.isTrue(equipmentFeeds.getPartitionId().equals(equipmentTarget.getPartitionId()), "Only allow feeds in same partition");
Equipment e1 = equipmentRepository.findById(equipmentFeeds).get();
Equipment e2 = equipmentRepository.findById(equipmentTarget).get();
e1.getFeeds().add(e2);
equipmentRepository.save(e1);
}
}
ManyToMany with composite key to self
@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinTable(name="FeedsRel",
joinColumns={
@JoinColumn(
name = "feedsrel_child_id",
referencedColumnName = "id"),
@JoinColumn(
name = "feedsrel_child_partitionId",
referencedColumnName = "partitionId")
})
private Set<Equipment> feeds = new HashSet<Equipment>();
// Associations marked as mappedBy must not define database mappings like @JoinTable or @JoinColumn
@ManyToMany( cascade = CascadeType.ALL, mappedBy="feeds", fetch = FetchType.EAGER)
private Set<Equipment> fedBy = new HashSet<Equipment>();


