Child primary key not updated by hibernate - spring

I'm using hibernate and spring data to save entities in my database. I'm attaching child elements to the parent and vice versa. Everything is saved correctly in the database, as well the child instances.
After calling save method again, the child elements get saved twice. I found out, that the reason is, that the framework does not update the childrens Id after persisting. It is always zero. Parent ID got updated correctly.
Any idea how to solve that?
Receipt.java:
#Entity
#javax.persistence.Table(name = "receipts")
public class Receipt {
private int id;
/*
* [...]
*/
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#OneToMany(fetch = FetchType.EAGER,cascade = CascadeType.ALL)
#JoinColumn(name = "receipt_id",referencedColumnName = "id")
private List<ReceiptItem> getReceiptItemList() {
return receiptItemList;
}
private void setReceiptItemList(List<ReceiptItem> receiptItemList) {
this.receiptItemList = receiptItemList;
}
/*
* [...]
*/
}
ReceiptItem.java:
#Entity
#Table(name = "receipt_items")
public class ReceiptItem {
private int id;
/*
* [...]
*/
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "receipt_id")
public Receipt getReceipt() {
return receipt;
}
public void setReceipt(Receipt receipt) {
this.receipt = receipt;
}
}
Saving:
item = new ReceiptItem();
item.setReceipt(receipt);
receipt.getReceiptItemList().add(item);
// this should create the new ReceiptItem instance
receiptService.save(receipt);
System.out.println("ItemId: "+item.getId()); //but the id is still 0
// calling save method twice results in a second entry in the database
// instead of updating the previously inserted one
receiptService.save(receipt);
System.out.println("ItemId: "+item.getId());
Output:
ItemId: 0
ItemId: 0

Related

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.

Spring JPA EntityGraph fetches all lazy loaded properties

I've worked with Spring and Hibernate. Now having a look at Spring Data JPA (2.0.3) with JPA 2.2
AgencyTicketType
#Entity
#Table(name = "agency_ticket_type", catalog = "test")
public class AgencyTicketType implements java.io.Serializable {
private Long id;
private String name;
private Agency agency;
private Set<AgencyTicketCategory> agencyTicketCategories = new HashSet<AgencyTicketCategory>(0);
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", unique = true, nullable = false)
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
#Column(name = "name", nullable = false, length = 100)
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "agency_id", nullable = false)
public Agency getAgency() {
return this.agency;
}
public void setAgency(Agency agency) {
this.agency = agency;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "agencyTicketType")
public Set<AgencyTicketCategory> getAgencyTicketCategories() {
return this.agencyTicketCategories;
}
public void setAgencyTicketCategories(Set<AgencyTicketCategory> agencyTicketCategories) {
this.agencyTicketCategories = agencyTicketCategories;
}
}
AgencyTicketCategory
#Entity
#Table(name = "agency_ticket_category", catalog = "waytest")
public class AgencyTicketCategory implements java.io.Serializable {
private Long id;
private AgencyTicketType agencyTicketType;
private String name;
private BigDecimal price;
private Set<TripTicket> tripTickets = new HashSet<TripTicket>(0);
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", unique = true, nullable = false)
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "agency_ticket_type_id", nullable = false)
public AgencyTicketType getAgencyTicketType() {
return this.agencyTicketType;
}
public void setAgencyTicketType(AgencyTicketType agencyTicketType) {
this.agencyTicketType = agencyTicketType;
}
#Column(name = "name", nullable = false, length = 100)
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
#Column(name = "price", nullable = false, precision = 8)
public BigDecimal getPrice() {
return this.price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "agencyTicketCategory")
public Set<TripTicket> getTripTickets() {
return this.tripTickets;
}
public void setTripTickets(Set<TripTicket> tripTickets) {
this.tripTickets = tripTickets;
}
}
Repository
public interface TicketTypeRepository extends JpaRepository<AgencyTicketType, Long> {
#EntityGraph(attributePaths={ "agencyTicketCategories" }, type=EntityGraphType.LOAD)
#Query("select type from AgencyTicketType type where type.agency.code=?1")
List<AgencyTicketType> findByAgency(String agencyCode);
}
Service
#Service
public class TicketServiceImpl implements TicketService {
#Autowired private TicketTypeRepository ticketType;
#Transactional(readOnly=true)
#Override
public List<AgencyTicketType> findByName(String code) {
return ticketType.findByAgency(code);
}
}
When debugged on Service, it seems, the query eagerly fetches all the lazy loaded properties - agency, agencyTicketCategories - and all their inner lazy loaded properties, which leads to JSON serilization error.
Need to fetch only these
AgencyTicketTypes [
{
id, name,
agencyTicketCategories [
{id,name,price},....
]
},.....
]
Can I do this with #EntityGraph? What I am missing?
Specifying lazy loading is only a hint for the JPA provider. Depending on the provider you use (Hibernate, EclipseLink etc.) it may be completely ignored and the dependencies may be eagerly fetched.
What you need to do is configure how your classes are mapped to json. Assuming you are using Jackson you may need to use annotations like #JsonIgnore or #JsonView. You may also map your class that only has the fields you need.
You can use Jackson annotations #JsonBackReference/#JsonManagedReference. They address problem of infinite recursion with bidirectional links in object model. As far as I understand it is your case.
See http://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion for more information.
One thing to point is that debugging while the transaction is open (touching the collection) will cause it to be loaded even if at real time it doesn't .. the other thing is that as #Apokralipsa mentioned , LAZY loading is just a hint that can be totally ignored and should never be relied upon whatever technique you are using

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;
}

One to many left join queries

Hi everyone,
I am new to hibernate JPA. Below is the relationship I defined between Entities A and B.
Here's the code for class A
class A{
#Id
#GeneratedValue
private Long id;
#Column(name = "col_1")
private Long col1;
#Column(name = "col_2")
private Long col2;
#OneToMany(fetch = FetchType.EAGER,mappedBy = "a")
private List<B> bList= new LinkedList<B>();
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public List<B> getBList() {
return bList;
}
public void setBList(List<B> bList) {
this.bList = bList;
}
}
And here's the code for class B
class B{
#Id
#GeneratedValue
private Long id;
#NotNull
#ManyToOne(optional=false)
#JoinColumns(value = { #JoinColumn(name = "col_1", referencedColumnName="col_1"),
#JoinColumn(name = "col_1", referencedColumnName="col_2") })
private A a;
#Column(name = "col_1")
private Long col1;
#Column(name = "col_2")
private Long col2;
public A getA() {
return a;
}
public void setA(A a) {
this.a = a;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
I have a crudrepository interface for A. When I run a crud method which loads A entity, I see one left outer join query for each record present in B mapped by col_1 and col_2 columns of A. All these queries are redundant. I am expecting only one left outer join query to be executed. This is causing timeouts in my application. Thanks for you help :)

Hibernate, Oracle, Sequence and One To Many Problem

I am having an issue with doing a one line save on a one to many object. That foreign key does not get populated in the child objects. Aren't they suppose to automatically from Hibernate? The BadgeID never gets inserted into the BadgeLevel.BadgeID.
Badge.java
#Basic
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="BADGE_SEQUENCE")
#SequenceGenerator(name="BADGE_SEQUENCE", sequenceName = "BADGE_SEQUENCE")
#Column(name = "ID", nullable=false, unique=true)
public Long getId() {
return id;
}
#OneToMany(mappedBy="badge", fetch=FetchType.EAGER, cascade=CascadeType.ALL)
#Fetch(value=FetchMode.SELECT)
public List<BadgeLevel> getBadgeLevels() {
return this.badgelevels;
}
BadgeLevel.java
#Basic
#Id
#NotNull
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="BADGELEVEL_SEQUENCE")
#SequenceGenerator(name="BADGELEVEL_SEQUENCE", sequenceName = "BADGELEVEL_SEQUENCE")
#Column(name = "ID", nullable=false, unique=true)
public Long getId() {
return id;
}
#ManyToOne()
#JoinColumn(name = "BADGEID")
public Badge getBadge() {
return this.badge;
}
/**
* set badge
*/
public void setBadge(Badge badge) {
this.badge = badge;
}
Before calling save on Badge, try the following
......
for(BadgeLevel badgeLevel : badge.getBadegeLevels()
{
badgeLevel.setBadge(badge);
}
repo.save(badge);

Resources