ManyToOne with jsonb Colum - spring-boot

There are my classes:
Parent
#Entity
#NoArgsConstructor
#Data
#AllArgsConstructor
public class Parent {
#Id
private String id;
private String name;
private String ssn;
#Valid
#Type(type = "json")
#Column(columnDefinition = "jsonb")
#OneToMany(mappedBy="parent ", cascade = CascadeType.ALL)
private List<Child> children;
}
Child
#Entity
#NoArgsConstructor
#Data
#AllArgsConstructor
public class Child implements Serializable {
#Id
private String name;
private String parentId;
#Valid
#Type(type = "json")
#Column(columnDefinition = "jsonb")
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "parentId", referencedColumnName = "id", insertable = false, updatable = false)
private Parent parent;
}
Parent Mapper
#Mapper
public interface ParentMapper {
#Mapping(target = "id", expression = "java(setId(parent.getName(), parent.getSsn()))")
ParentEntity toParentEntity(CreateParent parent);
Parent toParent(ParentEntity parentEntity);
default String setId(String name, String ssn) {
if (StringUtils.isNotEmpty(name) && StringUtils.isNotEmpty(ssn)) {
return String.format("%s+%s", name, ssn);
} else {
return null;
}
}
}
child mapper
#Mapper
public interface ChildMapper {
ChildEntity toChildEntity(CreateChild child, String parentId, String chaildName);
Child toChild(ChildEntity childEntity);
}
so there is an issue, creating and saving child object doesn't persist parent property of child object
Parent p = new Parent("somename","123456");
parentRepository.save(p);
Child c = new Child("somename");
c.setParentId(p.getId());
ChildEntity saved = childRepository.save(c);
saved.getParent() => returns null
ParentEntity savedParent = parentRepository.findById(p.getId());
savedParent.getChildren() => return null
Not sure what i done wrong ...

Related

Hibernate OneToOne relationship needs child value to be passed from parent domain object

I have created the below OneToOne relationship with Hibernate and Kotlin. However, when I am Initializing Parent() it requires me to set child value as Parent(child=null) which is not desired. Only initializing child should require parent as Child(parent=Parent(...) and if I add both parent to child and child to parent, it creates an infinite loop. What it the right way to avoid that?
#Entity
class Parent(
#Id
#Column(nullable = false, updatable = false, columnDefinition = "uuid")
val id: UUID = UUID.randomUUID(),
#OneToOne(cascade = [CascadeType.ALL], mappedBy = "parent")
#JsonIgnore
#JoinColumn(name = "child_id", referencedColumnName = "id")
val child: Child?
)
#Entity
class Subscriber(
#Id
#Column(nullable = false, updatable = false, columnDefinition = "uuid")
val id: UUID = UUID.randomUUID(),
#OneToOne(cascade = [CascadeType.ALL], optional = false)
#JoinColumn(name = "id", columnDefinition = "uuid")
#MapsId
val parent: Parent
)
As parent and child are mapped one to one and you want to use #MapsId to not create another extra PK in child table. Now Child object will use parent_id has its own PK.
For Parent
#Entity
public class Parent {
#Id
#Column(nullable = false, updatable = false, columnDefinition = "uuid")
private UUID id = UUID.randomUUID();
public UUID getId() {
return id;
}
public Parent setId(UUID id) {
this.id = id;
return this;
}
}
Child
#Entity
public class Child {
#Id
#Column(nullable = false, updatable = false, columnDefinition = "uuid")
private UUID id = UUID.randomUUID();
#OneToOne(fetch = FetchType.LAZY)
#MapsId
private Parent parent;
public UUID getId() {
return id;
}
public Child setId(UUID id) {
this.id = id;
return this;
}
public Parent getParent() {
return parent;
}
public Child setParent(Parent parent) {
this.parent = parent;
return this;
}
}
Check below screenshot for how table will look in database.

How to do a ManyToMany relationship insert

I am studying spring boot data using this API SWAPI, I did almost things but now I dont know how to map the relationship about two lists, above you can see my code and entities.
Entity Film
#Data
#Entity
public class Film extends Persistent<Long> {
private String title;
#JsonProperty(value = "episode_id")
private int episodeId;
#JsonProperty(value = "opening_crawl")
#Column(columnDefinition = "CLOB")
private String openingCrawl;
private String director;
private String producer;
#JsonDeserialize(converter = StringToLocalDateConverter.class)
#JsonProperty(value = "release_date")
private LocalDate releaseDate;
#JsonDeserialize(converter = ApiURLToEntitiesConverter.class)
#ManyToMany(mappedBy = "films")
private List<Person> characters;
#JsonDeserialize(converter = StringToLocalDateTimeConverter.class)
private LocalDateTime created;
#JsonDeserialize(converter = StringToLocalDateTimeConverter.class)
private LocalDateTime edited;
private String url;
}
Entity Person
#Data
#Entity
public class Person extends Persistent<Long> {
private String name;
private String height;
private String mass;
#JsonProperty(value = "hair_color")
private String hairColor;
#JsonProperty(value = "skin_color")
private String skinColor;
#JsonProperty(value = "eye_color")
private String eyeColor;
#JsonProperty(value = "birth_year")
private String birthYear;
private String gender;
#JsonDeserialize(converter = ApiURLToEntityConverter.class)
#JoinColumn(name = "planet_id", foreignKey = #javax.persistence.ForeignKey(name = "none"))
#OneToOne(optional = true)
private Planet homeworld;
#JsonDeserialize(converter = ApiURLToEntitiesConverter.class)
#ManyToMany
#JoinTable(
name = "film_person",
joinColumns = #JoinColumn(name = "film_fk", referencedColumnName = "id", nullable = true),
inverseJoinColumns = #JoinColumn(name = "person_fk", referencedColumnName = "id", nullable = true))
private List<Film> films;
#JsonDeserialize(converter = StringToLocalDateTimeConverter.class)
private LocalDateTime created;
#JsonDeserialize(converter = StringToLocalDateTimeConverter.class)
private LocalDateTime edited;
private String url;
}
I am trying to use the spring jpa method to saveAll
#Override
public List<T> insertAll(List<T> entities) {
for (Persistent entity : entities) {
Set<ConstraintViolation<Persistent>> violations = validator.validate(entity);
if (violations != null && !violations.isEmpty()) {
throw new ConstraintViolationException(violations);
}
}
return repository.saveAll(entities);
}
Converter Method
#Override
public List convert(List<String> s) {
if (s == null || s.isEmpty()) {
return null;
}
List objetos = new LinkedList();
for (String url : s) {
if (url.contains("people")) {
objetos.add(Util.getPerson(url));
}
if (url.contains("planets")) {
objetos.add(Util.getPlanet(url));
}
if (url.contains("starships")) {
objetos.add(Util.getStarship(url));
}
if (url.contains("vehicles")) {
objetos.add(Util.getVehicle(url));
}
if (url.contains("species")) {
objetos.add(Util.getSpecie(url));
}
}
return objetos;
}
}
Util method
public static Person getPerson(String characterApiUrl) {
if (characterApiUrl == null || characterApiUrl.isEmpty()) {
return null;
}
Person person = new Person();
person.setId(StringUtil.getIdEntity(characterApiUrl, "people/"));
return person;
}
The relationship table is being created but no populated

can i retrieve child entity containing parent entity id by using Spring Data Jpa one-to-many unidirectional relationship

Here is my parent entity:
#Entity
public class Parent {
#Id
int parentId;
String name;
#OneToMany()
#JoinColumn(name="parent_id")
List<Child> childList;
}
public class Child {
int childId;
//if i am taking this property as non-transient application won't run. but i need parent Id without changing the class structure..
#Transient
int parentId;
// ... some other properties
}
Insertion is successful as two tables are created : parent(id,name),
child(id,name,parent_id).
But when I retrieve the Parent record then in the Child object, the
parentId property remains 0.
i found a way to retrieve the parentid from the child entity by doing a bidirectional mapping of the Parent-child relationship. You can get the ParentId by using a getter method from the child entity that returns the parentId.
Parent Entity
#Entity
#Table(name = "Parent")
public class Parent implements Serializable {
#Column(name = "ID", nullable = false, length = 10)
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int Id;
#Column(name = "Name")
public String name;
#OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
private Set<Child> children = new HashSet<>();
public Parent() {
}
//getters and setters omitted for brevity
}
//Child Entity
#Entity
#Table(name = "Child")
public class Child implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int Id;
#Column(name = "Name")
private String name;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "parentId", nullable = false)
#OnDelete(action = OnDeleteAction.CASCADE)
private Parent parent;
public Child() {
}
public int getId() {
return Id;
}
public void setId(int id) {
Id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#JsonIgnore
public Parent getParent() {
return parent;
}
//getter method to retrieve the parent id in the child entity
public int getParent_Id(){
return parent.getId();
}
public void setParent(Parent parent) {
this.parent = parent;
}
}
Notice the method getParent_Id() which returns the parent Id, since getter methods are used to return object, the parentId would be returned as part of the child entity anytime it is fetched.
Also note the use of #JsonIgnore on the getParent() method, this to avoid an infinite recursion going on during serialization since Parent refers to Child and Child refer to Parent.

MIssing parent reference in a bidirectional hibernate mapping

I have a spring rest backend with two entities with a bidirectional relationshop (one-to-many, many to one). To overcome nested fetching issues, #JsonManagedReference/#JsonBackReference has been used for a perent/child relationship between entities.
The entites look as this:
#Entity
#Table(name = "Parent")
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Parent implements java.io.Serializable {
private Integer id;
private List<Child> childList;
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "ID", unique = true, nullable = false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
#OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
#JsonManagedReference
public List<Child> getChildList() {
return childList;
}
public void setChildListe(List<Child> childListe) {
this.childList = childList;
}
}
#Entity
#Table(name = "Child")
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Child implements java.io.Serializable {
private Integer id;
private Parent parent;
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "ID", unique = true, nullable = false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "ParentID")
#JsonBackReference
public Parent getParent() {
return parent;
}
public void setParent(Parent parent) {
this.parent = parent;
}
}
This works fine when fetching the Parent element, the childset is then fetched alongside and displayed as an json-array.
However, there is no reference to parent in the child element due to the usage of jsonbackreferance.
How can solve this issue ? I need parent reference when fetching child
That would lead to an infinite loop when serializing to JSON. That's the whole reason we don't do bi-direction JSON relationships.
What I would do is add an additional column to the child entity if you need the ID alone.
private Integer parentId;
#Column(name = "ParentID", insertable=false, updateable=false)
public Integer getParentId() {
return parentId;
}

how to rectify this mapping exception( Use of #OneToMany or #ManyToMany targeting an unmapped class)

Hi I am getting some mapping exception please follow the below error
org.hibernate.AnnotationException: Use of #OneToMany or #ManyToMany targeting an unmapped class: com.cmr.daos.child.domain.Child.medications[com.cmr.daos.child.domain.Medications]
at org.hibernate.cfg.annotations.CollectionBinder.bindManyToManySecondPass(CollectionBinder.java:1185)
at org.hibernate.cfg.annotations.CollectionBinder.bindStarToManySecondPass(CollectionBinder.java:710)
at org.hibernate.cfg.annotations.CollectionBinder$1.secondPass(CollectionBinder.java:645)
at org.hibernate.cfg.CollectionSecondPass.doSecondPass(CollectionSecondPass.java:65)
at org.hibernate.cfg.Configuration.originalSecondPassCompile(Configuration.java:1716)
at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1423)
at org.hibernate.cfg.Configuration.buildMappings(Configuration.java:1375)
at org.springframework.orm.hibernate3.LocalSessionFactoryBean.buildSessionFactory(LocalSessionFactoryBean.java:720)
at org.springframework.orm.hibernate3.AbstractSessionFactoryBean.afterPropertiesSet(AbstractSessionFactoryBean.java:188)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1571)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1509)
... 62 more
My domain class:
public class Child extends AuditProperties implements java.io.Serializable {
#Expose private Long childId;
#Expose private String firstName;
#Expose private String lastName;
private Set<Allergies> allergies = new HashSet<Allergies>();
private Set<Medications> medications = new HashSet<Medications>();
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "child")
#JsonManagedReference
public Set<Medications> getMedications() {
return this.medications;
}
public void setMedications(Set<Medications> medications) {
this.medications = medications;
}
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "child")
#JsonManagedReference
public Set<Allergies> getAllergies() {
return this.allergies;
}
public void setAllergies(Set<Allergies> allergies) {
this.allergies = allergies;
}
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "CHILD_ID", unique = true, nullable = false)
public Long getChildId() {
return this.childId;
}
public void setChildId(Long childId) {
this.childId = childId;
}
#Column(name = "FIRST_NAME", nullable = false, length = 64)
public String getFirstName() {
return this.firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
#Column(name = "LAST_NAME", nullable = false, length = 64)
public String getLastName() {
return this.lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
Here my mapped classs:
public class Medications extends AuditProperties implements java.io.Serializable{
#Expose private Long medicationId;
#Expose private String hasMedication;
#Expose private String medicationType;
#Expose private transient Child child;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "CHILD_ID")
#JsonBackReference
public Child getChild() {
return child;
}
public void setChild(Child child) {
this.child = child;
}
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "MEDICATION_ID", unique = true, nullable = false)
public Long getMedicationId() {
return medicationId;
}
public void setMedicationId(Long medicationId) {
this.medicationId = medicationId;
}
#Column(name = "HAS_MEDICATION", nullable = false, length = 3)
public String getHasMedication() {
return hasMedication;
}
public void setHasMedication(String hasMedication) {
this.hasMedication = hasMedication;
}
#Column(name = "MEDICATION_TYPE", length = 64)
public String getMedicationType() {
return medicationType;
}
public void setMedicationType(String medicationType) {
this.medicationType = medicationType;
}
}
Here another mapped class:
#Entity
#Table(name = "ALLERGIES")
public class Allergies extends AuditProperties implements java.io.Serializable {
#Expose private Long allergyId;
#Expose private String hasAllergies;
#Expose private String allerigyType;
#Expose private transient Child child;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinColumn(name = "CHILD_ID")
#JsonBackReference
public Child getChild() {
return child;
}
public void setChild(Child child) {
this.child = child;
}
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "ALLERGY_ID", unique = true, nullable = false)
public Long getAllergyId() {
return allergyId;
}
public void setAllergyId(Long allergyId) {
this.allergyId = allergyId;
}
#Column(name = "HAS_ALLERGIES", length = 3)
public String getHasAllergies() {
return hasAllergies;
}
public void setHasAllergies(String hasAllergies) {
this.hasAllergies = hasAllergies;
}
#Column(name = "ALLERIGY_TYPE", length = 20)
public String getAllerigyType() {
return allerigyType;
}
public void setAllerigyType(String allerigyType) {
this.allerigyType = allerigyType;
}
}
Here i mentioned one child class, allergy class and medication class.Here i mapped child object to both the classes(allergy,medications) then i will get this exception.please help me abot this exception
As the exception says:
Use of #OneToMany or #ManyToMany targeting an unmapped class:
com.cmr.daos.child.domain.Child.medications[com.cmr.daos.child.domain.Medications]
Hibernate is trying to find the entity Medications that represents the property medications in your Child class.
Looking at the etities everything looks good, so I assume you missed to place #Entity for Medications class or you missed to mention about this entity in hibernate.cfg.xml file.

Resources