foreign key not getting copied to level 4 + jpa + hibernate - spring-boot

My Entity level is like this
Level One
#Entity
public class LevelOne {
#Id
private long levelOnePK;
#OneToMany(mappedBy = "levelOne")
private Set<LevelTwo> levelTwo;
//getters setters omitted
}
Level Two
#Entity
public class LevelTwo {
#Id
private long levelTwoPK;
#ManyToOne
#JoinColumn(name = "levelOnePK")
private LevelOne levelOne;
#OneToMany(mappedBy = "levelTwo")
private Set<LevelThree> levelThree;
//getters setters omitted
}
Level Three
#Entity
public class LevelThree {
#Id
private long levelThreePK;
#ManyToOne
#JoinColumn(name = "levelOnePK")
#JoinColumn(name = "levelTwoPK")
private LevelTwo levelTwo;
#OneToMany(mappedBy = "levelThree")
private Set<LevelFour> levelFour;
//getters setters omitted
}
Level Four // Not working. Why ??
#Entity
public class LevelFour {
#Id
private long levelFourPK;
#ManyToOne
#JoinColumn(name = "levelOnePK")
#JoinColumn(name = "levelTwoPK")
#JoinColumn(name = "levelThreePK")
private levelThree levelThree;
//getters setters omitted
}
For the fourth level the error is "It is not mapped to a single entity"
It works upto level 3 and does not at level 4. I want the primary / foreign key of every level go down to the level below. I am joining using all the primary keys from the above tables but it does not work.
It works if i join only if I do the below in Level 4. But i want keys from above level as well.
#ManyToOne
#JoinColumn(name = "levelThreePK")
private levelThree levelThree;

Related

Is there a way to self-reference an entity using Spring JPA

I'm using Spring JPA and MySQL as the database. I have trouble with self-referencing its own entity.
I know the code below would do self-referencing, but it actually creates a new table to do so.
#Getter
#Entity
#NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Member extends BaseTimeEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "member_id")
private Long id;
#ManyToMany
#JoinColumn(name = "followings_id")
private List<Member> followings = new ArrayList<Member>();
#ManyToMany
#JoinColumn(name = "followers_id")
private List<Member> followers = new ArrayList<Member>();
#ManyToMany
#JoinColumn(name = "blocked_id")
private List<Member> blocked = new ArrayList<Member>();
...
}
Question: I'm wondering if I can do this in a single table(which would be the member table) without creating a new table to do many-to-many self-referencing.
It is possible,
Instead of using the #ManyToMany annotation, you can use the #OneToMany and #ManyToOne annotations to create the self-referencing relationship
#Getter
#Entity
#NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Member extends BaseTimeEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "member_id")
private Long id;
#OneToMany(mappedBy = "follower")
private List<Follow> followings = new ArrayList<>();
#OneToMany(mappedBy = "following")
private List<Follow> followers = new ArrayList<>();
#OneToMany(mappedBy = "blocker")
private List<Block> blocked = new ArrayList<>();
}
#Entity
#Getter
#NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Follow {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne
#JoinColumn(name = "follower_id")
private Member follower;
#ManyToOne
#JoinColumn(name = "following_id")
private Member following;
}
#Entity
#Getter
#NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Block {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne
#JoinColumn(name = "blocker_id")
private Member blocker;
#ManyToOne
#JoinColumn(name = "blocked_id")
private Member blocked;
}
Now Follow and Block entities represent the many-to-many relationships between Member entities and follower and following properties in the Follow entity represent the two sides of the many-to-many relationship, and the same is for blocked and blocker.

Composite primary key and ManyToOne hibernate

I'm learning Hibernate and I'm trying to make the Mapping work. My entities are as follows
Department:
#Entity
public class Department {
#Id
#GeneratedValue
private Integer id;
private String name;
private String hqLocation;
// getters and setters omitted for brevity
}
WorkerId:
#Embeddable
public class WorkerId implements Serializable {
private Integer workerId;
private Integer deptId;
// getters and setters omitted for brevity
}
Worker:
#Entity
public class Worker {
#EmbeddedId
private WorkerId id;
private String name;
private Integer age;
// How to make #ManyToOne mapping work?
private Department department;
// getters and setters omitted for brevity
}
Question: How to make #ManyToOne on the field private Department department; work? Simply adding the annotation results private Department department; as null.
I think you want to use a "derived identity"; so you should make Worker.department like this:
#Entity
public class Worker {
#EmbeddedId
private WorkerId id;
private String name;
private Integer age;
#MapsId("deptId")
#ManyToOne // <<<< edit
private Department department;
// getters and setters omitted for brevity
}
Derived identities are discussed (with examples) in the JPA 2.2 spec in section 2.4.1.
Question really is, which entity should be the owner of the relationship? would you like to map bidirectional or single way?
Here is the bidirectional example
#OneToMany(
fetch = FetchType.EAGER,
mappedBy = "department",
orphanRemoval = true,
cascade = CascadeType.ALL)
private List<Worker> workers;
#JoinColumn(name = "department_id", nullable = false)
#ManyToOne(targetEntity = Department.class, fetch = FetchType.LAZY)
private Department department;
fetch types are optional and depend on the use case

#OnetoMany entity in #ElementCollection

I have 2 entities and 1 embeddable object :
#Entity
class CourseDetails extends Course {
#Id
Integer id;
#ElementCollection
#CollectionTable(name = "course_section", joinColumns = #JoinColumn(name = "courseId"), foreignKey = #ForeignKey(name = "course_section_fk"))
private List<CourseSection> courseSection;
}
#Embeddable
public class CourseSection extends BaseBo {
#OneToMany
#JoinColumn(name="contentId")
private Set<CourseContent> courseContent = new HashSet<>();
}
#Entity
public class CourseContent {
private static final long serialVersionUID = 1856738483334146418L;
#Id
private Integer contentId;
private String contentSummary;
}
I want to store coursesection as an embedded object of course and course_section should contain reference of course_content. I tried the above structure but it gives error :
#ElementCollection cannot be used inside an #Embeddable that is also contained within an #ElementCollection
How to achieve this in spring boot-jpa ?

How to create JPA Specification for multiple tables?

I had entities User, BlockUnit, Block and Unit as Follows.
User has ManyToMany relation with blockunit.
#Entity
public class User {
#ManyToMany
private Set<BlockUnit> blockUnits;
}
#Entity
public class BlockUnit {
#Id
private Long id;
#OneToOne(targetEntity = Block.class)
#JoinColumn(name = "block_id")
private Block block;
#OneToOne(targetEntity = Unit.class)
#JoinColumn(name = "unit_id")
private Unit unit;
#ManyToMany(fetch = FetchType.LAZY)
private Set<User> users = new HashSet<>();
}
BlockUnit has OneToOne relation with Block and Unit.
#Entity
public class Block {
#Id
private Long id;
}
#Entity
public class Unit {
#Id
private Long id;
}
How should I create the JPA criteria specification for above in order to select user's having Block ID and Unit ID?
Thank you very much in advance!

JPA one to many, fetch children with specific column value

I have two entities in one to many relationship in my spring-data-jpa project.
Parent entity -
#Entity
#Table(name = "code_group")
public class CodeGroup implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
#NaturalId
#Column(nullable = false)
private String entityId;
#OneToMany
#JoinColumn(name = "codeGroupId", referencedColumnName = "entityId")
private List<SystemCode> systemCodes;
// .. getters setters
}
Child entity -
#Entity
#Table(name = "system_code")
public class SystemCode implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
#Column(nullable = false)
private String codeGroupId;
#Column(nullable = false)
#Enumerated(EnumType.STRING)
private ActiveOrInactive status;
// getters and setters
}
status column is of enum type, it can only have Active or Inactive value.
My existing code works fine. It is fetching code group with associated system codes. I want to filter system code with status='Active'. How to do this?
Try like this:
#OneToMany
#JoinColumn(name = "codeGroupId", referencedColumnName = "entityId")
#Where(clause = "status= 'Active'")
private List<SystemCode> systemCodes;
You can create such methods in your repo:
List<CodeGroup> getAllBySystemCodes_Status(ActiveOrInactive status);
default List<CodeGroup> getAllActive() {
return getAllBySystemCodes_Status(ActiveOrInactive.Active);
}
default List<CodeGroup> getAllInactive() {
return getAllBySystemCodes_Status(ActiveOrInactive.Inactive);
}

Resources