I'm working with spring boot and thymeleaf as template engine, when i tried to use Spring JPA method findAllByPropertyTitleContainning, i had StackOverflowError
Property.class
package com.example.estateagencyspring.models;
import lombok.Data;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
#Entity
#Data
public class Property {
#Id
private String id;
private String propertyTitle;
private String propertyDescription;
private String location;
private String type;
private String status;
private String area;
private String beds;
private String baths;
private String garage;
private String defaultPicture;
private String price;
#Lob
private String googleSrc;
#OneToMany(mappedBy="property")
private List<Picture> pictures = new ArrayList<>();
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(
name = "property_amenity",
joinColumns = #JoinColumn(name = "property_id"),
inverseJoinColumns = #JoinColumn(name = "amenity_id")
)
private List<Amenity> amenities = new ArrayList<>();
}
this code of Amenity class, it has #ManyToMany relationship with Property class
Amenity.class
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import java.util.ArrayList;
import java.util.List;
#Entity
#Data
public class Amenity {
#Id
private String id;
private String name;
#ManyToMany(mappedBy = "amenities", fetch = FetchType.LAZY)
private List<Property> properties = new ArrayList<>();
}
PropertyRepository.class
public interface PropertyRepository extends JpaRepository<Property, String> {
Optional<Property> findByPropertyTitle(String title);
List<Property> findAllByPropertyTitleContaining(String title);
}
PropertyService.class
...
public List<Property> searchByTitle(String title){
System.out.println(propertyRepository.findAllByPropertyTitleContaining(title));
return propertyRepository.findAllByPropertyTitleContaining(title);
}
Related
I am in the process of adding a DTO layer to a restful api. Before, the program used entity (Recipe and Ingredient) directly and now I added a new DTO layer in between (RecipeDTO IngredientDTO). However, the moment I made the change I started getting Null values from #RequestBody. Each recipe contains a list of Ingredients and it is the list of ingredients that are returning null values, the recipe by itself is returning fine.
The controller looks like this
package com.example.recipes.controller;
import com.example.recipes.DTO.RecipeDTO;
import com.example.recipes.Service.RecipeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/*...*/
#PostMapping(path = "/post")
public void postRecipes(#RequestBody RecipeDTO recipeDTO){
recipeService.postRecipes(recipeDTO);
}
/*...*/
Recipe Entity
package com.example.recipes.Entity;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.time.LocalDateTime;
import java.util.List;
#Data
#Entity
#Table(name = "recipe", schema = "public")
#AllArgsConstructor
#NoArgsConstructor
public class Recipe {
#Id
#GeneratedValue(
strategy = GenerationType.IDENTITY
)
#Column(name = "id", updatable = false, nullable = false)
private long id;
#Column(name = "name")
private String name;
#Column(name = "instructions")
private String instructions;
#OneToMany(mappedBy = "recipe")
private List<Ingredient> ingredients;
#JsonProperty("date_added")
private String dateAdded = String.valueOf(LocalDateTime.now());
#JsonProperty("last_edited")
private String lastEdited = String.valueOf(LocalDateTime.now());
}
RecipeDTO
package com.example.recipes.DTO;
import lombok.*;
import javax.persistence.OneToMany;
import java.time.LocalDateTime;
import java.util.List;
#AllArgsConstructor
#NoArgsConstructor
#Getter
#Setter
#ToString
public class RecipeDTO {
private long id;
private String name;
private String instructions;
private List<IngredientDTO> ingredientsDTO;
private String dateAdded = String.valueOf(LocalDateTime.now());
private String lastEdited = String.valueOf(LocalDateTime.now());
public RecipeDTO(long id, String name, String instructions, String dateAdded, String lastEdited) {
this.id = id;
this.name = name;
this.instructions = instructions;
this.dateAdded = dateAdded;
this.lastEdited = lastEdited;
}
}
Ingredient Entity
package com.example.recipes.Entity;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import javax.persistence.*;
#Data
#Entity
#Table(name = "Ingredient")
#NoArgsConstructor
public class Ingredient {
#Id
#GeneratedValue(
strategy = GenerationType.IDENTITY
)
#JsonProperty("ingredient_id")
private long ingredient_ID;
#JsonProperty("ingredient_name")
private String ingredientName;
#Column(name = "amount")
private int amount;
#Column(name = "unit")
private String unit;
#ManyToOne
#JoinColumn(name = "recipe_id")
#ToString.Exclude
#JsonIgnore
private Recipe recipe;
}
IngredientDTO
package com.example.recipes.DTO;
import lombok.*;
#Data
#AllArgsConstructor
#NoArgsConstructor
public class IngredientDTO {
private long ingredientID;
private String ingredientName;
private int amount;
private String unit;
}
the json i sent
{
"name":"unique2",
"ingredients":[
{
"ingredient_name":"Atlantic",
"amount":13,
"unit":"ton"
},
{
"ingredient_name":"Pacific",
"amount":15,
"unit":"boatload"
},
{
"ingredient_name":"Indian",
"amount":38,
"unit":"trucload"
}
],
"instructions":"easy on the salt"
}
and the #requestbody the ingredientsDTO is null
this is recipe: RecipeDTO(id=0, name=unique2, instructions=easy on the salt, ingredientsDTO=null, dateAdded=2022-08-08T15:04:10.678748100, lastEdited=2022-08-08T15:04:10.678748100)
Edit: I have just tried copying the code from the entity classes and pasting them in the DTO classes and it still returning null...
package com.example.recipes.DTO;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.time.LocalDateTime;
import java.util.List;
#Data
#Entity
#Table(name = "recipe", schema = "public")
#AllArgsConstructor
#NoArgsConstructor
public class RecipeDTO {
#Id
#GeneratedValue(
strategy = GenerationType.IDENTITY
)
#Column(name = "id", updatable = false, nullable = false)
private long id;
#Column(name = "name")
private String name;
#Column(name = "instructions")
private String instructions;
#OneToMany(mappedBy = "recipeDTO")
private List<IngredientDTO> ingredientDTOs;
#JsonProperty("date_added")
private String dateAdded = String.valueOf(LocalDateTime.now());
#JsonProperty("last_edited")
private String lastEdited = String.valueOf(LocalDateTime.now());
public RecipeDTO(long id, String name, String instructions, String dateAdded, String lastEdited) {
this.id = id;
this.name = name;
this.instructions = instructions;
this.dateAdded = dateAdded;
this.lastEdited = lastEdited;
}
}
package com.example.recipes.DTO;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import javax.persistence.*;
#Data
#Entity
#Table(name = "Ingredient")
#NoArgsConstructor
public class IngredientDTO {
#Id
#GeneratedValue(
strategy = GenerationType.IDENTITY
)
#JsonProperty("ingredient_id")
private long ingredientID;
#JsonProperty("ingredient_name")
private String ingredientName;
#Column(name = "amount")
private int amount;
#Column(name = "unit")
private String unit;
#ManyToOne
#JoinColumn(name = "recipe_id")
#ToString.Exclude
#JsonIgnore
private RecipeDTO recipeDTO;
public IngredientDTO(long ingredientID, String ingredientName, int amount, String unit) {
this.ingredientID = ingredientID;
this.ingredientName = ingredientName;
this.amount = amount;
this.unit = unit;
}
}
#RequestBody
this is recipe: RecipeDTO(id=0, name=unique2, instructions=easy on the salt, ingredientDTOs=null, dateAdded=2022-08-08T15:24:19.325806500, lastEdited=2022-08-08T15:24:19.325806500)
these are the ingredients: null
this is ingredientDTO: null
this is ingredientDTO: null
Edit2: I tried posting only the ingredientDTO and the #RequestBody was able to pick it up just fine
//this is fine
public void testRecipePost(#RequestBody IngredientDTO ingredientDTO) {
System.out.println("ingredientDTO: " + ingredientDTO);
}
You can replace
#OneToMany(mappedBy = "recipeDTO")
private List<IngredientDTO> ingredientDTOs;
to
#OneToMany(mappedBy = "recipeDTO")
private List<IngredientDTO> ingredients;
Or adding
#JsonProperty("ingredients")
Example:
#JsonProperty("ingredients")
#OneToMany(mappedBy = "recipeDTO")
private List<IngredientDTO> ingredientDTOs;
The reason for null is because Jackson doesn't know how to deserialise your fields properly with different names.
In the json, the name is ingredients but, in the DTO, it is ingredientsDTO. Those 2 need to match.
You request
{
"name":"unique2",
"ingredients":[...]
here the name of array you are passing in Json is different in the entity you are using.
Your DTO
#OneToMany(mappedBy = "recipeDTO")
private List<IngredientDTO> ingredientDTOs;
The name of fields in JSON request and Entity must match.
Change the name of field private List<IngredientDTO> ingredientDTOs; to ingredients.
I am trying to use the #OneToMany relationship in my project but got the error: org.hibernate.AnnotationException: Illegal attempt to map a non collection as a #OneToMany, #ManyToMany or #CollectionOfElements: com.digitalProfile.digitalProfile.entity.Education.faculty.
I am using JDK 11
My Education.java model looks like this :
package com.digitalProfile.digitalProfile.entity;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
#Entity
#Table(name="Education")
public class Education extends BaseEntity {
private String name;
private String establishDateNepali;
private String establishDateEnglish;
#OneToOne
private OwnedType ownedType;
private double area;
private int teacherCount;
private int studentCount;
private int staffCount;
#OneToOne
private AcademicLevel academicLevel;
#OneToMany(mappedBy = "education", fetch = FetchType.LAZY,
cascade = CascadeType.ALL)
private Faculty faculty;
private String province;
private String district;
private String munvdc;
private String ward;
private String gauntole;
private String streetname;
private String city;
//getter setter
and Faculty.java look like this :
package com.digitalProfile.digitalProfile.entity;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
#Entity
#Table
public class Faculty extends BaseEntity{
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "education_id", nullable = false)
private Education education;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
and base entity:
package com.digitalProfile.digitalProfile.entity;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
#MappedSuperclass
public class BaseEntity {
#Id
#Column(nullable = false, unique = true)
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Temporal(TemporalType.TIMESTAMP)
#CreationTimestamp
#Column(updatable = false)
private Date dateCreated;
#Temporal(TemporalType.TIMESTAMP)
#UpdateTimestamp
private Date dateUpdated;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Date getDateCreated() {
return dateCreated;
}
public void setDateCreated(Date dateCreated) {
this.dateCreated = dateCreated;
}
public Date getDateUpdated() {
return dateUpdated;
}
public void setDateUpdated(Date dateUpdated) {
this.dateUpdated = dateUpdated;
}
}
You currently have defined your Education class to have a single reference variable to Faculty:
public class Education extends BaseEntity {
private Faculty faculty;
}
But if you want to have a OneToMany relationship From Education To Faculty that means that one Education object needs to have references to multiple Faculty objects. So you need to change your data structure so that your Education class can hold multiple references to Faculty objects.
This is usually done by defining the field as a Collection like List:
public class Education extends BaseEntity {
private List<Faculty> faculties;
}
If you are saying Education can have multiple faculties, then it should be defined as
#OneToMany(mappedBy = "education", fetch = FetchType.LAZY,
cascade = CascadeType.ALL)
private Set<Faculty> faculties;
I have the following classes:
A Product class:
package com.springtraining.hibernate.invoice;
import lombok.Getter;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.List;
#NoArgsConstructor
#Getter
#Entity
#Table(name="PRODUCTS")
public class Product {
#Id
#GeneratedValue
#NotNull
#Column(name = "ID")
private int id;
#Column(name = "NAME")
private String name;
#OneToMany(
targetEntity = Item.class,
mappedBy = "product",
cascade = CascadeType.ALL,
fetch = FetchType.LAZY
)
private List<Item> items = new ArrayList<>();
public Product(String name) {
this.name = name;
}
}
package com.springtraining.hibernate.invoice.dao;
import com.springtraining.hibernate.invoice.Product;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import javax.transaction.Transactional;
#Repository
#Transactional
public interface ProductDao extends CrudRepository<Product, Integer> {
}
Now, an Item class:
package com.springtraining.hibernate.invoice;
import lombok.Getter;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
#NoArgsConstructor
#Getter
#Entity
#Table(name="ITEMS")
public class Item {
#Id
#GeneratedValue
#NotNull
#Column(name = "ID")
private int id;
#JoinColumn(name = "PRODUCT_ID", referencedColumnName = "id")
#ManyToOne
private Product product;
#NotNull
#Column(name = "PRICE")
private BigDecimal price;
#NotNull
#Column(name = "QUANTITY")
private int quantity;
#NotNull
#Column(name = "VALUE")
private BigDecimal value;
#JoinColumn(name="INVOICE_ID", referencedColumnName = "id")
#ManyToOne
private Invoice invoice;
public Item(Product product, String price, int quantity) {
this.product = product;
this.product.getItems().add(this);
this.price = new BigDecimal(price);
this.quantity = quantity;
this.value = this.price.multiply(new BigDecimal(quantity));
}
public void setInvoice(Invoice invoice) {
this.invoice = invoice;
invoice.getItems().add(this);
}
}
package com.springtraining.hibernate.invoice.dao;
import com.springtraining.hibernate.invoice.Item;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import javax.transaction.Transactional;
#Repository
#Transactional
public interface ItemDao extends CrudRepository<Item, Integer> {
}
And an Invoice class:
package com.springtraining.hibernate.invoice;
import lombok.Getter;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.List;
#NoArgsConstructor
#Getter
#Entity
#Table(name="INVOICES")
public class Invoice {
#Id
#GeneratedValue
#NotNull
#Column(name = "ID")
private int id;
#NotNull
#Column(name = "NUMBER")
private String number;
#OneToMany(
targetEntity = Item.class,
mappedBy = "invoice",
cascade = CascadeType.ALL,
fetch = FetchType.LAZY
)
private List<Item> items = new ArrayList<>();
public Invoice(String number) {
this.number = number;
}
}
package com.springtraining.hibernate.invoice.dao;
import com.springtraining.hibernate.invoice.Invoice;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import javax.transaction.Transactional;
#Repository
#Transactional
public interface InvoiceDao extends CrudRepository<Invoice, Integer> {
}
Now, when I am running a unit test with these classes, I get the following error:
org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : com.springtraining.hibernate.invoice.Item.product -> com.springtraining.hibernate.invoice.Product; nested exception is java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : com.springtraining.hibernate.invoice.Item.product -> com.springtraining.hibernate.invoice.Product
org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : com.springtraining.hibernate.invoice.Item.product -> com.springtraining.hibernate.invoice.Product; nested exception is java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : com.springtraining.hibernate.invoice.Item.product -> com.springtraining.hibernate.invoice.Product
The unit test code looks like such:
package com.springtraining.hibernate.invoice.dao;
import com.springtraining.hibernate.invoice.Invoice;
import com.springtraining.hibernate.invoice.Item;
import com.springtraining.hibernate.invoice.Product;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.Arrays;
#RunWith(SpringRunner.class)
#SpringBootTest
public class InvoiceDaoTestSuite {
#Autowired
private InvoiceDao invoiceDao;
#Test
public void testInvoiceDaoSave() {
// Given
Product product1 = new Product("prod1");
Product product2 = new Product("prod2");
Item item1 = new Item(product1, "100", 10);
Item item2 = new Item(product1, "200", 10);
Item item3 = new Item(product2, "50", 2);
Item item4 = new Item(product2, "250", 25);
Invoice invoice1 = new Invoice("HK-47");
item2.setInvoice(invoice1);
item3.setInvoice(invoice1);
Invoice invoice2 = new Invoice("HK-48");
item1.setInvoice(invoice2);
item4.setInvoice(invoice2);
// When
invoiceDao.save(invoice1);
invoiceDao.save(invoice2);
int invoice1_id = invoice1.getId();
int invoice2_id = invoice2.getId();
// Then
Assert.assertNotEquals(0, invoice1_id);
Assert.assertNotEquals(0, invoice2_id);
Assert.assertTrue(invoice1.getItems().containsAll(Arrays.asList(item2, item3)));
Assert.assertTrue(invoice2.getItems().containsAll(Arrays.asList(item1, item4)));
Assert.assertTrue(product1.getItems().containsAll(Arrays.asList(item1, item2)));
Assert.assertTrue(product1.getItems().containsAll(Arrays.asList(item3, item4)));
// Clean-up
try {
invoiceDao.deleteById(invoice1_id);
invoiceDao.deleteById(invoice2_id);
} catch (Exception e) {
// Do nothing
}
}
}
I have been looking at this code for a few hours now, and I still do not get it, where I have missed something. Saving Invoice entity, should automatically instantiate Item and Product objects associated with it as well.
Anyone?
In public class Item, add #ManyToOne cascade = CascadeType.ALL property, like so:
#JoinColumn(name = "PRODUCT_ID", referencedColumnName = "id")
#ManyToOne(cascade = CascadeType.ALL)
private Product product;
#JoinColumn(name = "INVOICE_ID", referencedColumnName = "id")
#ManyToOne(cascade = CascadeType.ALL)
private Invoice invoice;
When you create a new entity, using the keyword new, it is in the Transient state. To persist/save it to the DB, you first need to add it to the Persistence Context. CascadeType.ALL includes CascadeType.PERSIST, which will instruct Hibernate to persist the product and invoice entities.
Also, remove the #NotNull on your entity fields annotated by #Id. It is not required, since your field is a primary key and instead of this
invoiceDao.save(invoice1);
invoiceDao.save(invoice2);
int invoice1_id = invoice1.getId();
int invoice2_id = invoice2.getId();
You can do:
int invoice1_id = invoiceDao.save(invoice1).getId();
int invoice2_id = invoiceDao.save(invoice2).getId();
I am creating one feeds table which has one to many mapping with comments and many to one mapping with users table. But when i am annotating the user_table field in my feeds entity as #ManyToOne i am getting error like #OneToOne or #ManyToOne on xxx references an unknown entity: java .util.Set but when i am annotating it with #ManyToMany it is not throwing any error and the table are getting created. Can anyone explain me why
package com.incture.metrodata.entity;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
#Entity
#Getter
#Setter
#ToString
#Table(name = "FEEDS_DETAILS")
public class FeedsDo implements BaseDo {
/**
*
*/
private static final long serialVersionUID = -2035537433672391211L;
#Id
#Column(name = "FEED_ID")
private String feedId;
#Column(name = "BODY")
private String body;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "CREATED_AT")
private Date createdAt;
#Column(name = "CREATED_BY")
private String createdBy;
#Column(name = "TITLE")
private String title;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "UPDATED_AT")
private Date updatedAt;
#Column(name = "UPDATED_BY")
private String updatedBy;
#Column(name = "IS_DELETED")
private int isDeleted = 0;
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinTable(name = "FEEDS_USERS", joinColumns = { #JoinColumn(name = "FEED_ID")}, inverseJoinColumns = { #JoinColumn(name = "USER_ID") })
private Set<UserDetailsDo> user = new HashSet<UserDetailsDo>(0);
#OneToMany(targetEntity = CommentsDo.class, fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private List<CommentsDo> comments;
#Override
public Object getPrimaryKey()
{
return feedId;
}
}
package com.incture.metrodata.entity;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
#Entity
#Table(name = "COMMENTS")
public class CommentsDo implements BaseDo {
/**
*
*/
private static final long serialVersionUID = 5180603287069572120L;
#Id
#Column(name = "COMMENT_ID")
#GeneratedValue(strategy = GenerationType.AUTO)
private long commentId;
#Lob
private String comment;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "CREATED_AT")
private Date createdAt;
#Column(name = "CREATED_BY")
private String createdBy;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "UPDATED_AT")
private Date updatedAt;
#Column(name = "IS_DELETED")
private int isDeleted=0;
#Override
public Object getPrimaryKey() {
return commentId;
}
}
package com.incture.metrodata.entity;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.Lob;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.hibernate.annotations.ColumnDefault;
import org.hibernate.annotations.DynamicUpdate;
import org.hibernate.annotations.Where;
import lombok.Data;
import lombok.ToString;
#Entity
#Data
#ToString
#Table(name = "USER_DETAILS")
#DynamicUpdate(true)
#Where(clause = "DELETE = 0")
public class UserDetailsDo implements BaseDo {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "USER_ID",length=50)
private String userId;
#Column(name = "FIRST_NAME",length=100)
private String firstName;
#Column(name = "LAST_NAME",length=100)
private String lastName;
//#Formula(value = " concat(FIRST_NAME, ' ', LAST_NAME) ")
#Column(name = "NAME",length=100)
private String name;
#ManyToOne(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
private RoleDetailsDo role;
#Column(name = "TELEPHONE",length=50)
private String telephone;
#Column(name = "CREATED_BY",length=50)
private String createdBy;
#Column(name = "UPDATED_BY",length=50)
private String updatedBy;
#Column(name = "MOBILE_TOKEN")
#Lob
private String mobileToken;
#Column(name = "WEB_TOKEN")
#Lob
private String webToken;
#Column(name = "LONGITUDE")
private Double longitude;
#Column(name = "LATITUDE")
private Double latitude;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "CREATED_DATE")
private Date createdDate;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "CREATED_AT")
private Date createdAt;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "UPDATED_AT")
private Date updateAt;
#Column(name = "EMAIL",length=100)
private String email;
#Column(name = "PARENT_ID",length=100)
private String parentId;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "LAST_LOGIN_TIME")
private Date lastLogedIn;
#Column(name = "TRACK_FREQUENCY")
#ColumnDefault("'30'")
private Long trackFreq;
#ManyToMany(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
#JoinTable(name = "USERS_WAREHOUSE_MAPPING", joinColumns = { #JoinColumn(name = "USER_ID") }, inverseJoinColumns = {
#JoinColumn(name = "WARE_HOUSE_ID") })
private Set<WareHouseDetailsDo> wareHouseDetails = new HashSet<WareHouseDetailsDo>(0);
#ManyToMany(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
#JoinTable(name = "USERS_COURIER_MAPPING", joinColumns = { #JoinColumn(name = "USER_ID") }, inverseJoinColumns = {
#JoinColumn(name = "COURIER_ID") })
private Set<CourierDetailsDo> courierDetails = new HashSet<CourierDetailsDo>(0);
#Column(name = "DELETE")
#ColumnDefault("'0'")
private Integer deleted = 0;
public void setDeleted() {
this.deleted = 1;
}
#Override
public Object getPrimaryKey() {
return userId;
}
}
You have a one-directional relationship:
#OneToMany(targetEntity = CommentsDo.class, fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private List<CommentsDo> comments;
And hibernate doesn't know, which column to use to join those entities. The best would be to add relationship definition on child side. You need to specify #JoinColumn, something like:
#JoinColumn(name = "feeds_do_id")
private FeedsDo feedsDo;
in CommentsDo class. Instead of feeds_do_id there should be a foreign key.
I am new with hibernate and jpa. I need a little help. I'm developing a restful service application with spring boot. Using mysql and hibernate.
When i call my service "ingredients" array will be empty like that.
Empty array
In database ingredient table and recipe table has one to many relationship so i tried to do same thing with JPA but i can't find correct way. When I try to get Recipe i can access but ingredient list is always empty.
My Database Design:
DB Design
Recipe Entity:
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
#Entity()
#Table(name="recipe")
#Getter
#Setter
public class Recipe {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "recipe_id")
private int recipeId;
#Column(name ="name")
private String name;
#Column(name = "description")
private String description;
#Column(name = "picture_id")
private int pictureId;
#OneToMany(mappedBy = "recipe",fetch = FetchType.EAGER)
private List<Ingredient> ingredients = new ArrayList<>();
}
Ingredient Entitiy:
import lombok.Getter;
import lombok.Setter;
import javax.persistence.*;
import java.io.Serializable;
#Entity()
#Table(name = "ingredient")
#Getter
#Setter
public class Ingredient implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ingredient_id")
private int ingredientId;
#Column(name = "scale")
private String scale;
#ManyToOne
#JoinColumn(name = "recipe_id",nullable = false)
private Recipe recipe;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "material_id",nullable = false)
private Material material;
}
RecipeDAO:
import com.mutfak.dolapservice.dao.interfaces.IRecipeDAO;
import com.mutfak.dolapservice.entity.Recipe;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.List;
#Transactional
#Repository
public class RecipeDAO implements IRecipeDAO {
#PersistenceContext
private EntityManager entityManager;
#SuppressWarnings("unchecked")
#Override
public List<Recipe> getRecipes() {
String query = "FROM Recipe ORDER BY recipe_id";
return (List<Recipe>) entityManager.createQuery(query).getResultList();
}
#Override
public Recipe getRecipeByMaterial(int materialId) {
return null;
}
#Override
public Recipe getRecipeById(int id) {
return null;
}
#Override
public void addRecipe(Recipe recipe) {
}
#Override
public void updateRecipe(Recipe recipe) {
}
#Override
public void deleteRecipe(int id) {
}
}
Finally I find solution. Lombok annotation's and JPA doesn't work correctly. JPA can't get List<> with Lombok.