Showing posts with label One to many. Show all posts
Showing posts with label One to many. Show all posts

Thursday, 8 December 2022

Using Composite Key in Hibernate With Spring Boot

 This post contains an example showing how we can use a composite key in hibernate with spring.


We have an employee that has multiple tasks. I am not posting the DB, the reason is that I have turned on the ddl-auto to true. If you need to automatically update the DB when spring loads the entities, add the following property to the application.properties file.

spring.jpa.hibernate.ddl-auto=update

Coming back to the code part. Here is an Employee class.

import com.fasterxml.jackson.annotation.JsonManagedReference;
import java.io.Serializable;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import lombok.Data;
import lombok.RequiredArgsConstructor;

@Data
@RequiredArgsConstructor
@Entity
public class Employee implements Serializable {
@Id
private long employeeId;
private String name;
private String dept;
@JsonManagedReference
@OneToMany(mappedBy = "employee")
List<Task> taskList;

}
and the following section contains the Task class


import com.fasterxml.jackson.annotation.JsonBackReference;
import java.io.Serializable;
import java.sql.Date;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.ManyToOne;
import javax.persistence.MapsId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Entity
@AllArgsConstructor
@NoArgsConstructor
public class Task implements Serializable {
@EmbeddedId
private CompositeTaskId taskId;

@JsonBackReference
@MapsId("employeeKey")
@ManyToOne
private Employee employee;

private String taskName;
private Date date;
}
and CompositeTaskId

import java.io.Serializable;
import javax.persistence.Embeddable;
import lombok.Data;
import lombok.RequiredArgsConstructor;

@Data
@RequiredArgsConstructor
@Embeddable
public class CompositeTaskId implements Serializable {
private long employeeKey;
private long taskId;

}
Running the code with controllers will create DB  given table and composite key.


P.S. I have re-used code from some example online as well but don't remember the reference link.

Tuesday, 24 August 2021

Hibernate associations

The following post is for playing with the assiocations.


Uni-directional

 public class SourceEntity {

@Id

private Long id;

private String name;

@OneToMany

private List<TargetEntity> targets;

}

public class TargetEntity {
@Id
private Long id;
private String description;
}

Both tables have two columns each. No FK column is added.

For the able table, the third table is "source_entity_targets" is created with two columns "source_entity_id" and "target_id".

Bi-directional

If I add convert it to bi-directional, still it will create a third table. Following changes are added for bi-directional and Target Entity looks like. 

public class TargetEntity {

@Id
private Long id;
private String description;
@ManyToOne(fetch = FetchType.LAZY)
    private SourceEntity sourceEntity;
}

This time the target entity table has "source_entity_id" column as well. It is "MUL" key.

Adding @JoinColumn annotation in Source table


public class SourceEntity {
@Id
private Long id;
private String name;
        @OneToMany(cascade = {CascadeType.ALL})
@JoinColumn
private List<TargetEntity> targets;
}

public class TargetEntity {

@Id
private Long id;
private String description;

@ManyToOne(fetch = FetchType.LAZY)
private SourceEntity sourceEntity;

}

This creates two tables. The source table has 2 columns, Target tables have 4 columns out of which 2 columns are: source_entity_id and targets_id. 

On saving the object, the source_entity id was saved in target_ids.

Join Column name

When I added the name to the Join column annotation as following in the source entity class.

Two tables were created.

@OneToMany(cascade = {CascadeType.ALL})
@JoinColumn(name="source_id")
private List<TargetEntity> targets;

Target table's column name "targets_id" is converted to "source_id".

When I added the @JoinColumn annotation in targetClass as 
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="source_id")
private SourceEntity sourceEntity;

Three tables were created.
source_entity has 2 columns.
The target entity has now 3 columns. The third column is "source_id".
And source_entity_targets table with two columns as discussed above.

When saved an object, the source_id was set to null and the source_entity_targets columns had values.

After adding the following to source
@OneToMany(cascade = {CascadeType.ALL}, mappedBy = "sourceEntity") 
private List<TargetEntity> targets;

2 tables were created but the source id was not saved in the target table. the source_id column value was set to null.

To fix this, a new sourceEntity should be added to the target entity before saving the source entity. Example: 

SourceEntity src = new SourceEntity();
src.setName("source");
List<TargetEntity> targetEntities = new ArrayList<>();
TargetEntity target = new TargetEntity();
target.setDescription("description");
target.setSourceEntity(src); // <<<<< this line adds the source to target.
targetEntities.add(target);
src.setTargets(targetEntities);
dataService.persistData(src);