JPA Parent Child relationship on same entity(view) - java

I have a view which has a parent-child relationship. So I have my entity this way:
#Entity
#Table(name = "assessment_v", schema = "hlt_hrsc")
public class HrscLabellingAssessmentVEntity {
#Id
private String id;
#Column(name = "child_id")
private String childId;
#ManyToOne(cascade = {CascadeType.ALL})
#JoinColumn(name = "id")
private HrscLabellingAssessmentVEntity parent;
#OneToMany(mappedBy = "parent")
private Set<HrscLabellingAssessmentVEntity> child = new HashSet<>();
}
when I start my application it throws an error :
nested exception is org.hibernate.MappingException: Could not determine type for: java.util.Set
Please find the below image of the view for parent child eg:
id child_id
120.35871 120.35872
120.35872 null
Here 120.35872 is the parent record and 120.35871 is the child record. The parentId is maintained on the child_id column. My requirement is when I try to fetch the parent it should have the child records also.
what am I doing wrong??

Please check this example
#Entity
#Table(name = "assessment_v", schema = "hlt_hrsc")
public class HrscLabellingAssessmentVEntity {
#Id
private String id;
#Column(name = "child_id")
private String childId;
#JsonBackReference
#JoinColumn(name = "parent_id", referencedColumnName = "id")
#ManyToOne(fetch = FetchType.LAZY)
#Fetch(FetchMode.JOIN)
private HrscLabellingAssessmentVEntity parentId;
#JsonManagedReference
#OneToMany(mappedBy = "parentId", cascade = CascadeType.ALL)
private Set<HrscLabellingAssessmentVEntity> child = new HashSet<>();
}

Related

Hibernate parent child 1-to-1 relationship with child id in parent table

This inserts the parent (vehicle) but doesn't insert anything into the child table. I'm new to hibernate, is there something wrong here or is my problem elsewhere?
#Entity
#Table(schema = "mydb", name = "vehicles")
#Data
public class Vehicles {
#Id
#Column(name = "idvehicle")
private Long idVehicle;
#Column(name = "color")
private String color;
#Column(name = "passengers")
private Double passengers;
// field idcar (fk) must have the idcar field (pk) of the child
#OneToOne(cascade= CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
#JoinColumn(name = "idcar", columnDefinition = "serial")
private Car car;
}
#Entity
#Table(schema = "mydb", name = "cars")
#Data
public class Cars {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "idcar", columnDefinition = "serial")
private Long idCar;
#Column(name = "owner")
private String owner;
}

HIbernate ignore fetching data from OnetoMany field

I would like to ignore #OnetoMany field in my entity. fetch data need to get actual fields but don't want to fire query to dependent table. But deleting data from parent table needs deletion from dependent table
I have tried #Transient that ignores but the delete is also being ignored. Is there any other option to tell JPA not to fetch data from childs table when i call the parent entity?
#Entity
Table(name = "User")
public class UserEntity implements Serializable {
#Id
#Column(name = "id")
private int id;
#Column(name = "SERIAL", unique = true, nullable = false)
private String serial;
#OneToMany(mappedBy = "serialBySerialId", cascade = CascadeType.ALL)
private Set<UserActionEntity> userActionsById;
}
#Table(name = "user_action")
public class UserActionEntity implements Serializable {
#Id
#Column(name = "id")
private int id;
#Column(name = "action")
private String action;
#ManyToOne
#JoinColumn(name = "USER_ID", referencedColumnName = "ID", nullable = false)
private UserEntity userByUserId;
If you don't want to fire query to dependent table, you can use (fetch = FetchType.LAZY) on UserActionEntity property.
#OneToMany(mappedBy = "serialBySerialId", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<UserActionEntity> userActionsById;

Cascade delete on entity with #ElementCollection

I have a problem when cascade deleting my Parent entity:
org.postgresql.util.PSQLException: UPDATE or DELETE on table "child" violates constraint "XXX": for key (id)=(4) there are references in table "child_properties"
#Entity
#Table(name = "Parent")
public class Parent{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToMany(fetch = FetchType.EAGER,mappedBy = "parent")
#OnDelete(action = OnDeleteAction.CASCADE)
private Set<Child> children;
}
#Entity
#Table(name = "child")
public class Child{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne
#JoinColumn(name = "parent_id")
private Parent parent;
#ElementCollection(fetch = FetchType.EAGER)
private Map<String,String> properties;
}
I expected child to delete its properties on parentRepository.delete(parent)
but this only happens on childRepository.delete(child). parent delete throws exception
the solution was ~3 hours googling...
the idea is to set custom foreign key
#ElementCollection(fetch = FetchType.EAGER)
#CollectionTable(name = "child_properties"
,joinColumns = {
#JoinColumn(name = "child_id"
, referencedColumnName = "id"
,foreignKey=#ForeignKey(name="CHILD_PROPERTY_FK"
, foreignKeyDefinition = "FOREIGN KEY (child_id) references public.child (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE CASCADE"))
}
)
#MapKeyColumn(name = "name")
#Column(name = "value")
private Map<String,String> properties;

Hibernate loads list collection twice

I have 3 tables in my database, container, item and item_container which is a join_table of many to one between container and item. Entities in code are mapped using 2 classes: Container and Item.
The relation is unidrectional from Container to Item.
join_table in hibernate is mapped only by annotations in Container class.
#Entity
#Table(name="container")
public class Container {
#Id
#Column(name = "container_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
#JoinTable(name = "item_container",
joinColumns = #JoinColumn(name = "container_id"),
inverseJoinColumns = #JoinColumn(name = "item_id"))
private Set<Item> items;
//getter/setters
}
My problem is: when i have the type of collection Set<Item> items changed to List<Item>, the list contain every Item entity twice. I cant find the reason why, the hashCode and equals methods of Item are based only on the item_id field.
UPDATE:
Code for Item class:
#Entity
#Table(name = "item")
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
public class Item {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "item_id")
private Long id;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "item_template_id", nullable = false)
private ItemTemplate itemTemplate;
#Column(name = "item_group")
#Enumerated(EnumType.STRING)
private ItemGroup itemGroup;
#Column(name = "amount")
private int amount;
//getter/setters
}

Hibernate Bidirectional one-to-many with composite key

I am trying to create a bidirectional one-to-many association between two entities where the many side has a compound key. And one of the keys of the many side is coming from the one side. Also, I need to have the many side the owner of the association. Below is an example code showing what my code looks like.
Without Jointable
Parent Class which is the one side. I need to have this side owner of the association.
public class parent{
#Id
#Column(name = "NAME")
private String name;
#OneToMany(fetch=FetchType.LAZY)
#JoinColumns({
#JoinColumn(name="NAME", nullable = false),
#JoinColumn(name="PARENT", nullable = false)})
private Set<Child> childs;
}
Child Class which is the many side. Its primary key is "name" and "parent". "parent" is coming from the association.
public class child{
#EmbeddedId
#AttributeOverrides({
#AttributeOverride(name="parent", column=#Column(name="PARENT", nullable=false)),
#AttributeOverride(name="name", column=#Column(name="NAME", nullable=false))})
private ChildId id;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumns({
#JoinColumn(name="PARENT", nullable = false, updatable = false, insertable = false),
#JoinColumn(name="NAME", nullable = false, updatable = false, insertable = false)})
private Parent parent;
}
ChildId is the Embedded id.
#Embeddable
public class childId{
#Column(name = "PARENT")
private String parent;
#Column(name = "NAME")
private String name;
}
With Jointable
Parent Class
public class parent{
#Id
#Column(name = "NAME")
private String name;
#OneToMany(fetch = FetchType.LAZY)
#JoinTable(name="PARENTCHILD",
joinColumns= {#JoinColumn(name="PNAME", referencedColumnName = "NAME", nullable = false)},
inverseJoinColumns = {
#JoinColumn(name="CNAME", referencedColumnName = "NAME", nullable = false),
#JoinColumn(name="CPNAME", referencedColumnName = "PARENT", nullable = false)})
private Set<Child> childs;
}
Child Class
public class child{
#EmbeddedId
#AttributeOverrides({
#AttributeOverride(name="parent", column=#Column(name="PARENT", nullable=false)),
#AttributeOverride(name="name", column=#Column(name="NAME", nullable=false))})
private ChildId id;
#MapsId("parent")
#ManyToOne(fetch=FetchType.LAZY)
#JoinTable(name="PARENTCHILD",
inverseJoinColumns = {#JoinColumn(name="PNAME", referencedColumnName = "NAME", nullable = false)},
joinColumns = {
#JoinColumn(name="CNAME", referencedColumnName = "NAME", nullable = false),
#JoinColumn(name="CPNAME", referencedColumnName = "PARENT", nullable = false)})
private Parent parent;
}
Question1:
This code doesn't work. In case of "without jointable", it gives the below exception.
Caused by: org.hibernate.AnnotationException: A Foreign key refering com.entity.Parent from com.entity.Child has the wrong number of column. should be 1
Question2:
And in case of "with jointable", it gives below exception:
SQLCODE=-530, SQLSTATE=-23503, SQLERRMC=PARENTCHILD.FK_PARENTCHILD_CHILD
You don't need to keep Parent name as Id separately in Child , Hibernate will do that for you . I have made a simpler design .And you can control the relation by using mappedBy = childs ,in the #ManyToOne or mappedBy = parent in the #ManyToOne side.
#Entity
public class Parent{
#Id
private String name;
#OneToMany(fetch= FetchType.LAZY)
private Set<Child> childs;
public Parent(String name) {
this.name = name;
}
public Parent(){}
}
#Entity
public class Child{
#Id
private String name;
#ManyToOne(fetch=FetchType.LAZY)
private Parent parent;
}
Three tables will be generated by Hibernate
Child Table with columns name(Primary Key), parent_name(Foreign Key)
Parent Table with one column name(Primary Key)
Parent_child table with two columns parent_name and child_name
EDIT : Solution changed as per amir's needs, just add mappedBy whichever side you need to control the relationship.
#Entity
public class Child implements Serializable {
#Id
private String name;
#Id
#ManyToOne(fetch=FetchType.LAZY)
private Parent parent;
}
#Entity
public class Parent{
#Id
private String name;
#OneToMany(fetch= FetchType.LAZY)
private Set<Child> childs;
public Parent(String name) {
this.name = name;
}
public Parent(){}
}
EDIT - To name column in child side
#Id()
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="xyz")
private Parent parent;
To use One-To-Many bidirectional mapping using join table,use following code:
Parent Class
public class parent{
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
.....
.....
#OneToMany(cascade=CascadeType.ALL)
#JoinTable(name="Parent_Child", joinColumns={#JoinColumn(name ="parentId", referencedColumnName ="id")},
inverseJoinColumns={#JoinColumn(name ="childId", referencedColumnName ="id")})
private Set<Child> children;
.....
.....
}
Child Class
public class Child{
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
.....
.....
#OneToOne(cascade=CascadeType.ALL)
#JoinTable(name="Parent_Child", joinColumns={#JoinColumn(name ="childId", referencedColumnName ="id")},
inverseJoinColumns={#JoinColumn(name ="parentId", referencedColumnName ="id")})
private Parent parent;
.....
.....
}
Note that I have used OneTOMany mapping in Parent class - cause as per your logic a parent can have multiple children and I have used OneToOne mapping in Child class cause one child will have one parent(as mentioned in your requirements).
Hope this helps

Categories