I have a very large json to store and I divided that into following five entities and trying to store to h2 database using spring-data-jpa,inserting is working fine into database, but while fetching A object with A primary key Id, I am getting stackoverflow error, because there is circular dependency.
could someone help me to figure out what is the issue.
Top class
#Entity
#Table(name = "a")
#Data
public class A{
#Id
#Column(name = "a_id")
private String id;
#Column
private String name;
#Column
private String name2;
#Column
private String name3;
#Column
private String name4;
#Column
private String name5;
#OneToMany(cascade = CascadeType.ALL,mappedBy = "a",fetch =
FetchType.EAGER)
#JsonManagedReference
private List<B> b;
}
Second class
#Entity
#Table(name = "b")
#Data
public class B{
#Id
#Column(name = "bname")
private String bname;
#Column
private String bVersion;
#OneToMany(cascade = CascadeType.ALL,mappedBy = "b")
#JsonManagedReference
private List<C> cs;
#ManyToOne
#JoinColumn(name = "a_id")
#JsonBackReference
private A a;
}
Third class
#Entity
#Data
public class C{
#Id
#Column(name = "cname")
private String cName;
#Column
private String cVersion;
#OneToMany(cascade = CascadeType.ALL,mappedBy = "c")
#JsonManagedReference
private List<D> ds;
#ManyToOne
#JoinColumn(name = "bname")
#JsonBackReference
private B b;
}
Fourth class
#Entity
#Data
public class D{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="d_id")
private long id;
#Column
private String dName;
#Column
private String dName2;
#ElementCollection
#Column
private List<String> dNames;
#OneToMany(cascade = CascadeType.ALL,mappedBy = "d")
#JsonManagedReference
private List<E> e;
#ManyToOne
#JoinColumn(name = "cname")
#JsonBackReference
private C c;
}
Fifth class
#Entity
#Data
public class E{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "e_id")
private long id;
#Column
private String ename;
#Column
private String eName2;
#ManyToOne
#JoinColumn(name = "e_id")
#JsonBackReference
private E e;
}
I also faced the same problem and spent the whole day. Finally, I found its problem with the toString method generated by Lombok using #Data annotation.
Solution:
Override, toString method and write your own implementation. If you do not want to use toString then use #Getter and #Setter instead of #Data.
Why
Note: This occurs with bi-directional relationship.
Lets say I have two entity and having bi-directional relationship.
#data
Entity1{
#oneToMany
public List<Entity2> entity2s;
//Added by lombok while using #Data
#Generated
public String toString() {
return "entity2s=" + this.getEntity2s() + ")";
}
}
#data
Entity2{
#ManytoOne
public Entity1 entity1;
//Added by lombok while using #Data
#Generated
public String toString() {
return "entity1=" + this.getEntity1() + ")";
}
}
In above example, toString()(called by JPA) of Entity1 calles toString() of Entity2 and toString() of Entity2 calls toString() of Entity1. And that is how circular reference is building.
Note: The same goes to hashCode method.
Here is a some reference links,
https://github.com/rzwitserloot/lombok/issues/1007
https://interviewbubble.com/stackoverflow-tostring-method-when-using-lombok/
Related
I have already built projects similar to this one, I even based this one in a different project I have. Thing is, I don't see why it keeps failing when I try to save an object to the Database. These are my Classes:
Car
#Data
#AllArgsConstructor
#NoArgsConstructor
#Entity(name = "cars")
public class Car {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column
#NotBlank
private String brand;
#Column
#NotBlank
private String model;
#Column
#NotBlank
private String color;
#Column
#NotBlank
private int kilometers;
#Column(name = "fabrication_date")
private LocalDate fabricationDate;
#Column
#PositiveOrZero
private float price;
#Override
public String toString() {
return "------------------------------------------------------------"+ "\n"
+brand + " - " + model;
}
#OneToMany(mappedBy = "car")
#JsonBackReference(value = "car-purchases")
private List<Purchase> purchases;
}
Purchase
#Data
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name = "purchases",
uniqueConstraints = { #UniqueConstraint(columnNames =
{ "user_id", "car_id" }) })
public class Purchase {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(name = "creation_date")
private LocalDate creationDate;
#Column
private float price;
#ManyToOne
#JoinColumn(name = "user_id")
private User user;
#ManyToOne
#JoinColumn(name = "car_id")
private Car car;
}
This is the Add to Database function:
#Override
public CarOutDTO addCar(CarInDTO carInDTO) {
Car car = new Car();
modelMapper.map(carInDTO, car);
car.setFabricationDate(LocalDate.now());
car.setKilometers(0);
Car newCar = carRepository.save(car); <--- It fails here
CarOutDTO carOutDTO = new CarOutDTO();
modelMapper.map(car, carOutDTO);
return carOutDTO;
}
And, this is the info that comes when I try sending a POST:
I can't find the error here, I assume it has something to do with this part, maybe the #JsonBackReference part?
#OneToMany(mappedBy = "car")
#JsonBackReference(value = "car-purchases")
private List<Purchase> purchases;
I have 3 entity Unit, Off, Position. in my Unit have an constrain one to many with list offs, off have position. I want to Order by code in position.code, how can I make it
#Entity
#Table(name = "unit")
public class Unit{
#Id
#Column(name = "id")
private Long id;
#OneToMany(fetch = FetchType.LAZY)
#JoinClolumn(name = "unit")
#ElementCollection
#OrderBy("position.code")
private List<Off> offs;
}
this is my Entity Off
#Entity
#Table(name = "off")
#Embeddable
public class Off{
#Id
#Column(name = "id")
private Long id;
#Column(name = "cate_position")
private Long catePosition;
#ManyToOne
#NotFound(action = NotFoundAction.IGNORE)
#JoinClolumn(name = "cate_position")
#Embedded
private Position position;
}
this is my Entity Position
#Entity
#Table(name = "position")
#Embeddable
public class Position{
#Id
#Column(name = "id")
private Long id;
#Column(name = "code")
private String code;
}
How can I sort List offs in Unit entity by 'position.code', it always throws invalid column name 'position'. Many thanks!
Annotate the entity class Off with #Embeddable
and now include the following code above the List
#ElementCollection
#OrderBy("position.code DESC")
private List<Off> offs;
I am working on hibernate and tying to associate mapping with #OneToMany relationship with composite key.
Following are the entities that currently my using .
#Embeddable
#Getter
#Setter
public class AddressKey implements Serializable {
private static final long serialVersionUID = -307823488229761699L;
#Column(name = "id")
private Long id;
#Column(name = "city")
private Long city;
#Column(name = "locale")
private String locale;
#Column(name = "type")
private String type;
#ManyToOne
#JoinColumn(name="id")
private Person person;
}
#Entity
#Table(name = "address", schema = "test")
#Setter
#Getter
public class AddressHistory {
#EmbeddedId
private AddressKey key;
#Column(name = "active")
private boolean active;
#Column(name = "current")
private boolean current;
}
#Entity
#Table(name = "person", schema="test")
#ToString
public class Person {
#Id
#Column(name = "id")
private Long id;
#OneToMany(mappedBy="key.person", fetch=FetchType.EAGER, cascade=CascadeType.ALL)
private Set<AddressHistory> addressHistory;
}
But when I am trying to run this program it gives me following error.
repeated column in mapping for entity AddressHistory.
Someone help me to fix this what's wrong in this mapping.
Thanks in advance
You repeated columns. Remove #JoinColumn(name="id") in AddressKey since you already have one column with the same name or rename it to something else and more maintainable like person_id.
I have the following two classes.
School has many TestTakers
#Entity
#Table(name = "school")
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class School extends BaseModel {
#Column(name = "name")
private String name;
#OneToMany(mappedBy = "school")
// #JsonManagedReference <<<<< If not commented out, then error
private Set<TestTaker> testTakers;
//getter setters
}
// TestTaker.java
#Entity
#Table(name = "test_taker")
#JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class TestTaker extends BaseModel {
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#ManyToOne
#JoinColumn(name = "school_id")
#JsonBackReference("school_testTaker")
private School school;
//getters setters
}
Can anyone explain why #JsonManagedReference cannot be annotated on a collection? I would get an error saying Jackson cannot handle managed/back reference. How exactly does #JsonManagedReference work with #JsonBackReference in common DB relationships One-to-one, One-to-many, Many-to-one
I have read the documentation, still don't quite understand what Jackson is trying to achieve
Suppose, we have two entities, first one:
#Entity
#Table(name = "entitya")
public class EntityA {
#Id
#Column(name = "id")
private Long id;
#Column(name = "name")
private Long name;
#OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
private Set<EntityB> childEntities;
}
and the second:
#Entity
#Table(name = "entityb")
public class EntityB {
#Id
#Column(name = "id")
private Long id;
#Column(name = "name")
private String name;
#Column(name = "master")
private Boolean master;
#ManyToOne
#JoinColumn(name = "parent")
private EntityA parent;
}
So far, so good. However underlying database tables and constrains enforce that for any entityA there can be only one EntityB with boolean field master set to true. I can extract it by adding following method to entityA:
public entityB getMasterChild() {
for(entityB ent : childEntities) {
if(ent.isMaster()) {
return ent;
}
}
}
The question is, can I create #OneToOne relationship in EntityA that can express that rule, so that entityA can have additional masterChild member of type entityB?
If I understood you correctly you want to create/define a relationship between two entities based on a value of some entity's property. The think is that relationship between entities is defined on entities count (how many entities can has the other entity) and not on some entity's property value.
However
If you really want to use #OneToOne mapping for masterChild I would recommend creating a separate table/entity for it. Once this is done, you can include this new MasterChild entity into EntityA and annotate it with #OneToOne.
Here is new MasterChild entity
#Entity
public class MasterChild extends EntityB{
#Id
#Column(name = "id")
private Long id;
}
Note that I have removed 'master' from EntityB as it is no longer needed
#Entity
#Table(name = "entityb")
public class EntityB {
#Id
#Column(name = "id")
private Long id;
#Column(name = "name")
private String name;
#ManyToOne
#JoinColumn(name = "parent")
private EntityA parent;
}
And here is modified EntityA
#Entity
#Table(name = "entitya")
public class EntityA {
#Id
#Column(name = "id")
private Long id;
#Column(name = "name")
private Long name;
#OneToOne
private MasterChild master;
#OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
private Set<EntityB> childEntities;
}