How to prevent endless loop in hibernate - java

I have a rest server and client which uses this API. I have a list of hotels and it had passed well until I added bidirectional dependencies to other entities.After that I start receive an endless array of entities which just repeat the same row in database.
It is my first project with hibernate so may be I made trivial mistakes of novice.
Hotel:
#Entity
#Table(name = "hotels", schema = "", catalog = "mydb")
public class HotelsEntity implements HospitalityEntity{
private int idHotel;
private String name;
private String region;
private String description;
// private byte[] photo;
private HotelPropertyEntity property;
private List<RoomEntity> rooms;
#OneToOne(mappedBy = "hotel")
public HotelPropertyEntity getProperty() {
return property;
}
public void setProperty(HotelPropertyEntity property) {
this.property = property;
}
#OneToMany(mappedBy = "hotel")
public List<RoomEntity> getRooms() {
return rooms;
}
public void setRooms(List<RoomEntity> rooms) {
this.rooms = rooms;
}
#Id
#Column(name = "id_hotel", unique = true)
#GeneratedValue(strategy=GenerationType.AUTO)
public int getIdHotel() {
return idHotel;
}
public void setIdHotel(int idHotel) {
this.idHotel = idHotel;
}
#Basic
#Column(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Basic
#Column(name = "region")
public String getRegion() {
return region;
}
public void setRegion(String region) {
this.region = region;
}
#Basic
#Column(name = "description")
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
HotelProperty
#Entity
#Table(name = "hotel_property", schema = "", catalog = "mydb")
public class HotelPropertyEntity {
private int idHotelProperty;
private byte hasPool;
private byte hasTennisCourt;
private byte hasWaterslides;
private HotelsEntity hotel;
#Id
#Column(name = "id_hotel_property", unique = true)
#GeneratedValue(strategy=GenerationType.AUTO)
public int getIdHotelProperty() {
return idHotelProperty;
}
public void setIdHotelProperty(int idHotelProperty) {
this.idHotelProperty = idHotelProperty;
}
#Basic
#Column(name = "has_pool", columnDefinition = "BIT", length = 1)
public byte getHasPool() {
return hasPool;
}
public void setHasPool(byte hasPool) {
this.hasPool = hasPool;
}
#Basic
#Column(name = "has_tennis_court", columnDefinition = "BIT", length = 1)
public byte getHasTennisCourt() {
return hasTennisCourt;
}
public void setHasTennisCourt(byte hasTennisCourt) {
this.hasTennisCourt = hasTennisCourt;
}
#Basic
#Column(name = "has_waterslides", columnDefinition = "BIT", length = 1)
public byte getHasWaterslides() {
return hasWaterslides;
}
public void setHasWaterslides(byte hasWaterslides) {
this.hasWaterslides = hasWaterslides;
}
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "id_hotel_property")
public HotelsEntity getHotel() {
return hotel;
}
public void setHotel(HotelsEntity hotel) {
this.hotel = hotel;
}
Room:
#Entity
#Table(name = "room", schema = "", catalog = "mydb")
public class RoomEntity {
private int idRoom;
private String roomType;
private int peopleCapacity;
private Boolean booked;
private Boolean locked;
private HotelsEntity hotel;
private InventoriesEntity inventory;
private RoomPropertyEntity roomProperty;
#OneToOne(mappedBy = "room")
public RoomPropertyEntity getRoom() {
return roomProperty;
}
public void setRoom(RoomPropertyEntity roomProperty) {
this.roomProperty = roomProperty;
}
#OneToOne
#JoinColumn(name = "id_room")
public InventoriesEntity getInventory() {
return inventory;
}
public void setInventory(InventoriesEntity inventory) {
this.inventory = inventory;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "id_hotel")
public HotelsEntity getHotel() {
return hotel;
}
public void setHotel(HotelsEntity hotel) {
this.hotel = hotel;
}
#Id
#Column(name = "id_room")
public int getIdRoom() {
return idRoom;
}
public void setIdRoom(int idRoom) {
this.idRoom = idRoom;
}
#Basic
#Column(name = "room_type")
public String getRoomType() {
return roomType;
}
public void setRoomType(String roomType) {
this.roomType = roomType;
}
#Basic
#Column(name = "people_capacity")
public int getPeopleCapacity() {
return peopleCapacity;
}
public void setPeopleCapacity(int peopleCapacity) {
this.peopleCapacity = peopleCapacity;
}
#Basic
#Column(name = "booked", columnDefinition = "BIT", length = 1)
public Boolean getBooked() {
return booked;
}
public void setBooked(Boolean booked) {
this.booked = booked;
}
#Basic
#Column(name = "locked", columnDefinition = "BIT", length = 1)
public Boolean getLocked() {
return locked;
}
public void setLocked(Boolean locked) {
this.locked = locked;
}
Could you please advise what is a way or ways to tell hibernate to stop this cycle?
p.s
This code contains another one issue. I f I remove one to one dependency and remain only one to many I receive failed to lazily initialize a collection of role: com.example.model.HotelsEntity.rooms, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->com.example.model.HotelsEntity["rooms"])

You need to mark entity as not serializable for JSON. Please use #JsonIgnore or #JsonIgnoreProperties("field") on one of the sides of the relations (the annotation is class-level).

Related

Going around the many-to-many relationship in Spring boot, but no new entity is created

I'm using spring boot to construct a database using AWS RDS as well. I want to track down how many stars a user gives to different products. I learnt to go around the many-to-many relationship by creating a table connecting two one-to-many other tables. For this reason, I have created the following tables:
When a user rates a product, an api is called through the put command in order to track down which user(uid) rates which product(pid). When the product(pid) is not rated by anyone, a rate_item is created that contains the pid and also the uid. However, when another user (with a different uid) rates the same product (same pid), the rate_item is updated, which is a problem becausse supposedly, a new row containing the same pid and a different uid should be created, as seen in the following (user with "uid 1" has already rated the same product and when user with "uid 2" rates the same product, the entity gets updated, but not like a new entity is created):
ProductEntity:
#Entity
#Table(name = "product")
public class ProductEntity {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "pid",nullable = false)
private Integer pid;
#Column(name = "name", nullable = false)
private String name;
#Column(name="theme", nullable = false)
private String theme;
#Column(name="color", nullable = false)
private String color;
#Column(name="sizeZero", nullable = true)
private String sizeZero;
#Column(name="sizeOne", nullable = true)
private String sizeOne;
#Column(name="sizeTwo", nullable = true)
private String sizeTwo;
#Column(name="sizeThree", nullable = true)
private String sizeThree;
#Column(name="description",nullable = false)
private String description;
#Column(name = "image_url", nullable = false)
private String imageUrl;
#Column(name = "price",nullable = false)
private BigDecimal price;
#Column(name = "stock",nullable = false)
private Integer stock;
public ProductEntity(CreateProductData createProductData) {
this.pid = createProductData.getPid();
this.name = createProductData.getName();
this.theme =createProductData.getTheme();
this.color=createProductData.getColor();
this.sizeZero=createProductData.getSizeZero();
this.sizeOne =createProductData.getSizeOne();
this.sizeTwo =createProductData.getSizeTwo();
this.sizeThree =createProductData.getSizeThree();
this.description =createProductData.getDescription();
this.imageUrl = createProductData.getImageUrl();
this.price = createProductData.getPrice();
this.stock = createProductData.getStock();
}
public ProductEntity(){
}
public Integer getPid() {
return pid;
}
public void setPid(Integer pid) {
this.pid = pid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getTheme() {
return theme;
}
public void setTheme(String productType) {
this.theme = productType;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public String getSizeZero() {
return sizeZero;
}
public void setSizeZero(String sizeZero) {
this.sizeZero = sizeZero;
}
public String getSizeOne() {
return sizeOne;
}
public void setSizeOne(String smallSize) {
this.sizeOne = smallSize;
}
public String getSizeTwo() {
return sizeTwo;
}
public void setSizeTwo(String mediumSize) {
this.sizeTwo = mediumSize;
}
public String getSizeThree() {
return sizeThree;
}
public void setSizeThree(String largeSize) {
this.sizeThree = largeSize;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getImageUrl() {
return imageUrl;
}
public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
public Integer getStock() {
return stock;
}
public void setStock(Integer stock) {
this.stock = stock;
}
}
UserEntity:
#Entity
#Table(name="User")
public class UserEntity {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="uid",nullable = false)
private Integer uid;
#Column(name="username", nullable = false)
private String username;
#Column(name="email", nullable = false, unique = true)
private String email;
#Column(name="password", nullable = false)
private String password;
#Column(name = "firebase_uid", nullable = false)
private String firebaseUid;
#Column(name= "emailVerified", nullable = false,columnDefinition = "boolean default false")
private Boolean emailVerified=false;
#Column(name="subscribed", nullable = false)
private Boolean subscribed;
public UserEntity(UserEntity tempUserEntity){
this.uid=tempUserEntity.getUid();
this.firebaseUid=tempUserEntity.getFirebaseUid();
this.email=tempUserEntity.getEmail();
}
public UserEntity(CreateFirebaseUserData createFirebaseUserData){
this.username=createFirebaseUserData.getUsername();
this.email=createFirebaseUserData.getEmail();
this.password=createFirebaseUserData.getPassword();
this.firebaseUid= createFirebaseUserData.getFirebaseUid();
this.subscribed=createFirebaseUserData.getSubscribed();
}
public UserEntity(){
}
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getFirebaseUid() {
return firebaseUid;
}
public void setFirebaseUid(String firebaseUid) {
this.firebaseUid = firebaseUid;
}
public Boolean getEmailVerified() {
return emailVerified;
}
public void setEmailVerified(Boolean emailVerified) {
this.emailVerified = emailVerified;
}
public Boolean getSubscribed() {
return subscribed;
}
public void setSubscribed(Boolean subscribed) {
this.subscribed = subscribed;
}
}
RatingEntity:
#Entity
#Table(name="Rating")
public class ProductsRatedByUserEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="pruid")
private Integer pruid;
#OneToOne
#JoinColumn(name="pid",nullable = false)
private ProductEntity product;
#ManyToOne
#JoinColumn(name="uid",nullable = false)
private UserEntity user;
#Column
private Integer starsGiven;
#Column(name="total_stars", nullable = false)
private Integer totalStars;
#Column(name="total_num_of_users_who_rated", nullable = false)
private Integer totalNumOfUsersWhoRated;
#Column(name="average_stars")
private BigDecimal averageStars;
public ProductsRatedByUserEntity(UserEntity userEntity, ProductEntity productEntity, Integer numOfStars){
this.product=productEntity;
this.user=userEntity;
this.starsGiven=numOfStars;
this.totalStars=numOfStars;
this.totalNumOfUsersWhoRated=1;
this.averageStars=BigDecimal.valueOf(this.getTotalStars()).divide(BigDecimal.valueOf(this.getTotalNumOfUsersWhoRated()));
}
public ProductsRatedByUserEntity(ProductEntity product,UserEntity user,Integer numOfStars,Integer newTotalNumOfStars, Integer newTotalNumberOfUsers, BigDecimal averageStars){
this.product=product;
this.user=user;
this.starsGiven=numOfStars;
this.totalStars=newTotalNumOfStars;
this.totalNumOfUsersWhoRated=newTotalNumberOfUsers;
this.averageStars=averageStars;
}
public ProductsRatedByUserEntity(){
}
public Integer getPruid() {
return pruid;
}
public void setPruid(Integer plbuid) {
this.pruid = plbuid;
}
public ProductEntity getProduct() {
return product;
}
public void setProduct(ProductEntity product) {
this.product = product;
}
public UserEntity getUser() {
return user;
}
public void setUser(UserEntity user) {
this.user = user;
}
public Integer getStarsGiven() {
return starsGiven;
}
public void setStarsGiven(Integer starsGiven) {
this.starsGiven = starsGiven;
}
public Integer getTotalStars() {
return totalStars;
}
public void setTotalStars(Integer totalStars) {
this.totalStars = totalStars;
}
public Integer getTotalNumOfUsersWhoRated() {
return totalNumOfUsersWhoRated;
}
public void setTotalNumOfUsersWhoRated(Integer totalNumOfUsersWhoLiked) {
this.totalNumOfUsersWhoRated = totalNumOfUsersWhoLiked;
}
public BigDecimal getAverageStars() {
return averageStars;
}
public void setAverageStars(BigDecimal averageStars) {
this.averageStars = averageStars;
}
}
Api:
#CrossOrigin
#RestController
public class ProductApi {
private ProductService productService;
private ProductsRatedByUserService productsRatedByUserService;
#Autowired
public ProductApi(ProductService productService,ProductsRatedByUserService productsRatedByUserService){
this.productService=productService;
this.productsRatedByUserService=productsRatedByUserService;
}
#PutMapping("/product/rating/{pid}/{numOfStars}")
public ProductsRatedByUserResponseDto updateRating(#PathVariable Integer pid, #PathVariable Integer numOfStars, JwtAuthenticationToken jwtAuthenticationToken) throws ProductFoundByIdException {
FirebaseUserData firebaseUserData=new FirebaseUserData(jwtAuthenticationToken);
ProductsRatedByUserDetail productsRatedByUserDetail=productsRatedByUserService.updateProductRating(pid,numOfStars,firebaseUserData);
return new ProductsRatedByUserResponseDto(productsRatedByUserDetail);
}
}
RatingServiceImpl:
#Service
#Component
public class ProductsRatedByUserServiceImpl implements ProductsRatedByUserService {
public ProductsRatedByUserRepository productsRatedByUserRepository;
public ProductRepository productRepository;
public UserRepository userRepository;
#Autowired
public ProductsRatedByUserServiceImpl(ProductsRatedByUserRepository productsRatedByUserRepository,ProductRepository productRepository,UserRepository userRepository){
this.productsRatedByUserRepository=productsRatedByUserRepository;
this.productRepository=productRepository;
this.userRepository=userRepository;
}
#Override
public ProductsRatedByUserDetail updateProductRating(Integer pid, Integer numOfStars, FirebaseUserData firebaseUserData) throws ProductFoundByIdException {
if(!productRepository.existsById(pid)){
throw new ProductFoundByIdException();
}
UserEntity userEntity=userRepository.findUserEntityByEmail(firebaseUserData.getEmail());
ProductEntity productEntity =productRepository.findById(pid).orElse(null);
//check if the product has been rated by *any user*
//If no, we need to create an entity
if(!productsRatedByUserRepository.existsByProduct(productEntity)){
ProductsRatedByUserEntity productsRatedByUserEntity=new ProductsRatedByUserEntity(userEntity, productEntity, numOfStars);
ProductsRatedByUserEntity productsRatedByUserEntityReturned=productsRatedByUserRepository.save(productsRatedByUserEntity);
System.out.println("the product has been rated by *any user*");
return new ProductsRatedByUserDetail(productsRatedByUserEntityReturned);
}
//If yes, we update the entity from there
else {
//if the product has been rated by this very user
if (productsRatedByUserRepository.existsByUserAndProduct(userEntity, productEntity)) {
ProductsRatedByUserEntity productsRatedByUserEntity = productsRatedByUserRepository.findTopByUserAndProduct(userEntity, productEntity);
productsRatedByUserEntity.setTotalStars(productsRatedByUserEntity.getTotalStars() - productsRatedByUserEntity.getStarsGiven() + numOfStars);
productsRatedByUserEntity.setStarsGiven(numOfStars);
productsRatedByUserEntity.setAverageStars(BigDecimal.valueOf(productsRatedByUserEntity.getTotalStars()).divide(BigDecimal.valueOf(productsRatedByUserEntity.getTotalNumOfUsersWhoRated())));
ProductsRatedByUserEntity productsRatedByUserEntityReturned = productsRatedByUserRepository.save(productsRatedByUserEntity);
System.out.println("the product has been rated by this very user");
return new ProductsRatedByUserDetail(productsRatedByUserEntityReturned);
} else {
//The product has not been rated by this very user
ProductsRatedByUserEntity productsRatedByUserEntity = productsRatedByUserRepository.findTopByProduct(productEntity);
int newTotalNumOfStars = (productsRatedByUserEntity.getTotalStars() + numOfStars);
int newTotalNumberOfUsers = productsRatedByUserEntity.getTotalNumOfUsersWhoRated() + 1;
productsRatedByUserEntity.setUser(userEntity);
System.out.println("The product has not been rated by this very user");
return new ProductsRatedByUserDetail(productsRatedByUserRepository.save(new ProductsRatedByUserEntity(productEntity, userEntity, numOfStars, newTotalNumOfStars, newTotalNumberOfUsers, BigDecimal.valueOf(newTotalNumOfStars).divide(BigDecimal.valueOf(newTotalNumberOfUsers)))));
}
}
}
}
RatingServiceInterface:
public interface ProductsRatedByUserService {
ProductsRatedByUserDetail updateProductRating(Integer pid, Integer numOfStars, FirebaseUserData firebaseUserData) throws ProductFoundByIdException;
}
Repository:
public interface ProductsRatedByUserRepository extends CrudRepository<ProductsRatedByUserEntity,Integer> {
boolean existsByProduct(ProductEntity product);
ProductsRatedByUserEntity findTopByProduct(ProductEntity product);
boolean existsByUserAndProduct(UserEntity userEntity, ProductEntity product);
ProductsRatedByUserEntity findTopByUserAndProduct(UserEntity userEntity, ProductEntity product);
}
I will really appreciate anyone who can help me with this! I've been stuck for a whole day! I don't want to use the many-to-many annotation because it seems a bit messy. Thanks!
I have found the mistake. In my RatingEntity code, the getter and setter are erroneous. There's some typos there. It should be
public Integer getPruid() {
return pruid;
}
public void setPruid(Integer pruid) {
this.pruid = pruid;
}

Deleting child entity from set in parent class

I am trying to attach image files to an entity called product. I can create a product along with the image pretty well but when i try to delete an image i get the following error.
HTTP 500 - Request processing failed; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: com.IJM.model.Product
Product Class
#Entity
#Table(name = "Product")
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "Id")
private Long id;
#NotNull
#Size(min = 3, max = 10)
#Column(name = "Code", nullable = false)
private String code;
#NotNull
#Size(min = 3, max = 50)
#Column(name = "Name", nullable = false)
private String name;
#Size( max = 50)
#Column(name = "Description", nullable = false)
private String description;
#ManyToOne(cascade = CascadeType.MERGE)
#JoinColumn(name = "Id_Category")
private Category category;
#ManyToOne(cascade = CascadeType.MERGE)
#JoinColumn(name = "Id_Unit")
private Unit unit;
#OneToMany(cascade = CascadeType.ALL,
fetch= FetchType.EAGER,
orphanRemoval = true,
mappedBy="product")
private Set<Image> images;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
if(this.category==null||!this.category.equals(category))
{
this.category=category;
}
return;
}
public Unit getUnit() {
return unit;
}
public void setUnit(Unit unit) {
if(this.unit==null||!this.unit.equals(unit))
{
this.unit=unit;
}
return;
}
public Set<Image> getImages() {
return images;
}
public void setImages(Set<Image> images) {
this.images = images;
}
}
Image Class
#Entity
#Table(name = "product_Image")
public class Image {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="id", nullable = false)
private long id;
#Lob
#Column(name = "File", nullable = false)
private byte[] file;
#Column(name = "Checksum",nullable = false)
private String checksum;
#Column(name = "Extension",nullable = false)
private String extension;
#Column(name = "File_Name",nullable = false)
private String file_name;
#Column(name = "Size",nullable = false)
private int size;
#Column(name = "Last_Updated",nullable = false)
private Timestamp last_Updated;
#ManyToOne(cascade=CascadeType.ALL)
#JoinColumn(name="Id_Product")
private Product product;
#ManyToOne(cascade = CascadeType.MERGE)
#JoinColumn(name="Id_Directory")
private Directory directory;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public byte[] getFile() {
return file;
}
public void setFile(byte[] file) {
this.file = file;
}
public String getChecksum() {
return checksum;
}
public void setChecksum(String checksum) {
this.checksum = checksum;
}
public String getExtension() {
return extension;
}
public void setExtension(String extension) {
this.extension = extension;
}
public String getFile_name() {
return file_name;
}
public void setFile_name(String file_name) {
this.file_name = file_name;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public Timestamp getLast_Updated() {
return last_Updated;
}
public void setLast_Updated(Timestamp last_Updated) {
this.last_Updated = last_Updated;
}
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
public Directory getDirectory() {
return directory;
}
public void setDirectory(Directory directory) {
this.directory = directory;
}
And this is the code for the controller calling the deleting method
#RestController
#RequestMapping("/image")
public class ImageController {
#Autowired
ProductService productService;
#Autowired
ImageService imageService;
private static final String productImagePath="C:\\IJM\\Images\\Product\\";
#RequestMapping(value = "/product/{code}", method = RequestMethod.DELETE)
public ResponseEntity<Image> deleteProductImage(#PathVariable("code") String code) {
System.out.println("Fetching & Deleting Image for product " + code);
code = code.toUpperCase();
if (!productService.isProductExist(code)) {
System.out.println("Product with code " + code + " not found");
return new ResponseEntity<Image>(HttpStatus.NOT_FOUND);
}
else
{
Product product = productService.findProductByCode(code);
if(product.getImages()!=null)
{
for(Image image:product.getImages())
{
product.getImages().remove(image);
image.setProduct(null);
imageService.deleteImage(image.getId());
}
productService.saveProduct(product);
try{
File file = new File(productImagePath+code);
if(FileDeleter.removeDirectory(file)){
System.out.println(file.getName() + " is deleted!");
}else{
System.out.println("Delete operation is failed.");
}
}catch(Exception e){
e.printStackTrace();
}
}
}
return new ResponseEntity<Image>(HttpStatus.NO_CONTENT);
}
}
In case someone else is wondering.. the service just calls the DAO
#Override
public void deleteImage(long id) {
Image image = imageDao.findById(id);
imageDao.delete(image);
}
This is the Dao Class
#Repository("imageDao")
public class ImageDaoImpl extends AbstractDao<Long,Image> implements ImageDao{
#Override
public void delete(Image image) {
super.delete(image);
}
}
This is the code in my abstract DAO class
public void delete(T entity) {
getSession().delete(entity);
}
It seems these line are not in proper order.
product.getImages().remove(image);
image.setProduct(null);
imageService.deleteImage(image.getId());
Also not sure what imageService.deleteImage(image.getId()); is doing. It is not required.
Please try like below.
for(Image image:product.getImages())
{
image.setProduct(null);
product.getImages().remove(image);
}
productService.saveProduct(product);
This should be enough. I know it doesn't make any sense to change the order but It had worked for me.

Spring data Join multiple tables

This is it my database project:
I have a problem with the correct combination of tables, as it is in the picture.
This is my files:
Category.java
#Entity
public class Category {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
private String categoryName;
protected Category() {}
public Category(String categoryName) {
this.categoryName = categoryName;
}
public String getCategoryName() {
return categoryName;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public void setCategoryName(String categoryName) {
this.categoryName = categoryName;
}
#Override
public String toString() {
return String.format(
"Customer[id=%d, firstName='%s']",
id, categoryName);
}
}
Items.java
#Entity
#Table(name = "Items")
public class Items {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int ItemId;
private String ItemName;
private String price;
private Set<Locals> locals = new HashSet<Locals>(0);
public Items(){
}
public Items(String price, String itemName) {
this.price = price;
this.ItemName = itemName;
}
public void setItemId(int itemId) {
ItemId = itemId;
}
public void setLocals(Set<Locals> locals) {
this.locals = locals;
}
public void setPrice(String price) {
this.price = price;
}
public void setItemName(String itemName) {
ItemName = itemName;
}
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "ItemId", unique = true, nullable = false)
public int getItemId() {
return ItemId;
}
#ManyToMany(fetch = FetchType.LAZY, mappedBy = "itemsTo")
public Set<Locals> getLocals() {
return locals;
}
#Column(name = "price", nullable = false, length = 10)
public String getPrice() {
return price;
}
#Column(name = "ItemName", nullable = false, length = 10)
public String getItemName() {
return ItemName;
}
}
Locals.java
#Entity
#Table(name = "Locals")
public class Locals {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int LocalId;
private String localName;
private String address;
private String phoneNumber;
private String coorX;
private String coorY;
private Set<Items> itemsTo = new HashSet<Items>(0);
public Locals(){
}
public Locals(String localName,String address,String phoneNumber, String coorY, String coorX) {
this.coorY = coorY;
this.coorX = coorX;
this.phoneNumber = phoneNumber;
this.address = address;
this.localName = localName;
}
public Locals(String localName,String address,String phoneNumber, String coorY, String coorX, Set<Items> itemsTo) {
this.coorY = coorY;
this.coorX = coorX;
this.phoneNumber = phoneNumber;
this.address = address;
this.localName = localName;
this.itemsTo = itemsTo;
}
public void setLocalId(int localId) {
LocalId = localId;
}
public void setLocalName(String localName) {
this.localName = localName;
}
public void setAddress(String address) {
this.address = address;
}
public void setCoorX(String coorX) {
this.coorX = coorX;
}
public void setCoorY(String coorY) {
this.coorY = coorY;
}
public void setItemsTo(Set<Items> itemsTo) {
this.itemsTo = itemsTo;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "LocalId", unique = true, nullable = false)
public int getLocalId() {
return LocalId;
}
#Column(name = "localName", unique = false, nullable = false, length = 10)
public String getLocalName() {
return localName;
}
#Column(name = "address", unique = false, nullable = false, length = 10)
public String getAddress() {
return address;
}
#Column(name = "phoneNumber", unique = false, nullable = false, length = 10)
public String getPhoneNumber() {
return phoneNumber;
}
#Column(name = "coorX", unique = false, nullable = false, length = 10)
public String getCoorX() {
return coorX;
}
#Column(name = "coorY", unique = false, nullable = false, length = 10)
public String getCoorY() {
return coorY;
}
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "ItemsFinall", joinColumns = {
#JoinColumn(name = "LocalId", nullable = false, updatable = false) },
inverseJoinColumns = { #JoinColumn(name = "ItemId",
nullable = false, updatable = false) })
public Set<Items> getItemsTo() {
return itemsTo;
}
}
and ItemsFinall.java
#Entity
#Table(name = "ItemsFinall")
public class ItemsFinall {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
private int ItemId;
private int CategoryId;
private int LocalId;
public ItemsFinall(int id, int localId, int categoryId, int itemId) {
this.LocalId = localId;
this.CategoryId = categoryId;
this.ItemId = itemId;
this.id=id;
}
public void setId(int id) {
this.id = id;
}
public void setLocalId(int localId) {
LocalId = localId;
}
public void setCategoryId(int categoryId) {
CategoryId = categoryId;
}
public void setItemId(int itemId) {
ItemId = itemId;
}
public int getLocalId() {
return LocalId;
}
public int getCategoryId() {
return CategoryId;
}
public int getItemId() {
return ItemId;
}
public int getId() {
return id;
}
}
I get the following error: Caused by: org.springframework.data.mapping.PropertyReferenceException: No property categoryName found for type ItemsFinall!
I do not know what to do to properly connect the table.
ItemsServiceImpl.java
package dnfserver.model;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Created by Łukasz on 2015-03-14.
*/
#Component
public class CategoryServiceImpl implements CategoryService {
#Autowired
private CategoryRepository categoryRepository;
private Map<Integer,String> categoryMap = new HashMap<Integer, String>();
#Override
public Category create(Category category) {
Category createdCategory = category;
return categoryRepository.save(createdCategory);
}
#Override
public Category delete(int id) {
return null;
}
#Autowired
public Map<Integer,String> findAll(){
int i=0;
for (Category cat : categoryRepository.findAll()) {
categoryMap.put(i,cat.toString());
i++;
}
return categoryMap;
}
#Override
public Category update(Category shop) {
return null;
}
#Override
public Category findById(int id) {
return categoryRepository.findOne(id);
}
}
In hibernate/JPA you model the relationship between Entities, but not use plain Ids!
For example
#Entity
#Table(name = "ItemsFinall")
public class ItemsFinall {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
//instead of: private int ItemId;
#OneToMany
private Item item;
//instead of: private int CategoryId;
#OneToMany
private Category category;
//instead of: private int LocalId;
#OneToMany
private Local local;
...
(You also need to fix the Set<Locals> locals in item)

Accessing Object using JAXB in Spring-JPA application

Please help me in accessing Employee object in the below code using JAXB annotations. The application was developed in JPA SPRING. We are unable to access sub-object properties i.e, Employee properties
RESOURCE CORE FILE
#XmlAccessorType(XmlAccessType.PROPERTY)
#XmlRootElement(name="resource")
#Entity
#Table(name = "resource")
public class Resource implements java.io.Serializable {
private Integer resourceId;
private String resourceCode;
private String resourceName;
private String resourceNumber;
private Employee employee;
public Resource() {
}
public Resource(Employee employee,String resourceCode, String resourceName,
String resourceNumber
) {
this.employee = employee;
this.resourceCode = resourceCode;
this.resourceName = resourceName;
this.resourceNumber = resourceNumber;
}
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "resource_id", unique = true, nullable = false)
public Integer getResourceId() {
return this.resourceId;
}
public void setResourceId(Integer resourceId) {
this.resourceId = resourceId;
}
#Column(name = "resource_code")
public String getResourceCode() {
return this.resourceCode;
}
public void setResourceCode(String resourceCode) {
this.resourceCode = resourceCode;
}
#Column(name = "resource_number")
public String getResourceNumber() {
return this.resourceNumber;
}
public void setResourceNumber(String resourceNumber) {
this.resourceNumber = resourceNumber;
}
#Column(name = "resource_name")
public String getResourceName() {
return this.resourceName;
}
public void setResourceName(String resourceName) {
this.resourceName = resourceName;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "employee_id")
public Employee getEmployee() {
return this.employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
}
EMPLOYEE CORE FILE
#XmlAccessorType(XmlAccessType.PROPERTY)
#XmlRootElement(name="employee")
#Entity
#Table(name = "employee")
public class Employee implements java.io.Serializable {
private Integer employeeId;
private String employeeCode;
private String employeeName;
private List<Resource> resources = new ArrayList<Resource>(0);
public Employee() {
}
public Employee(String employeeCode, String employeeName,List<Resource> resources
) {
this.employeeCode = employeeCode;
this.employeeName = employeeName;
this.resources = resources;
}
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "employee_id", unique = true, nullable = false)
public Integer getEmployeeId() {
return this.employeeId;
}
public void setEmployeeId(Integer employeeId) {
this.employeeId = employeeId;
}
#Column(name = "employee_code")
public String getEmployeeCode() {
return this.employeeCode;
}
public void setEmployeeCode(String employeeCode) {
this.employeeCode = employeeCode;
}
#Column(name = "employee_name")
public String getEmployeeName() {
return this.employeeName;
}
public void setEmployeeName(String employeeName) {
this.employeeName = employeeName;
}
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "employee")
public List<Resource> getResources() {
return this.resources;
}
public void setResources(List<Resource> resources) {
this.resources = resources;
}
}
You have to use the FetchType : Eager in RESOURCE CORE FILE of getEmployee() Method. Lazy fetch type is pulling only the parent object. Eager is pulling both.

Cycle in Hibernate OneToMany relation

I use Hibernate and
have two entities(City and Region) with OneToMany relation.
the First:
#Entity
#Table(name = "p_region")
public class Region implements Serializable{
#OneToMany(mappedBy = "region",fetch= FetchType.LAZY, cascade = CascadeType.MERGE)
private List<City> citys;
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
//++++++++++++++++++++ GETSET
public List<City> getCitys() {
return citys;
}
public void setCitys(List<City> citys) {
this.citys = citys;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
and the second one:
#Entity
#Table(name = "p_city")
public class City implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#NotEmpty(message = "Название не должно быть пустым")
#Length(max = 10, min = 2, message = "Название должно быть менее 2 символов и не
более 100")
private String cityName;
#NotEmpty(message = "Код города не должно быть пустым")
private String cityCode;
#Column(name = "zone")
private Integer zone;
#Basic(optional = true)
#Temporal(javax.persistence.TemporalType.TIMESTAMP)
private Date entryDate = Calendar.getInstance().getTime();
#ManyToOne()
private Region region;
#Basic(optional = true)
private String zip_code;
// GET SET ::::::::::::::::::::::::::::::::::
public Integer getZone() {
return zone;
}
public void setZone(Integer zone) {
this.zone = zone;
}
public Region getRegion() {
return region;
}
public void setRegion(Region region) {
this.region = region;
}
public void delete() {
System.out.println("QQQQQQQQQQQQQQQQQQQQQQ");
}
public String getCityCode() {
return cityCode;
}
public void setCityCode(String cityCode) {
this.cityCode = cityCode;
}
public String getCityName() {
return cityName;
}
public void setCityName(String cityName) {
this.cityName = cityName;
}
public Date getEntryDate() {
return entryDate;
}
public void setEntryDate(Date entryDate) {
this.entryDate = entryDate;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getZip_code() {
return zip_code;
}
public void setZip_code(String zip_code) {
this.zip_code = zip_code;
}
}
When I try to get simple Object(City) with JSON it returns the cycle:
{"id":577,"region":{"name":"нет региона","id":15,"citys":[{"id":577,"region":
{"name":"нет региона","id":15,"citys":[{"id":577,"region":{"name":"нет
региона","id":15,"citys":[{"id":577,"region":{"name":"нет
региона","id":15,"citys":[{"id":577,"region":{"name":"нет
региона","id":15,"citys":[{"id":577,"region":{"name":"нет
региона","id":15,"citys":[{"id":577,"region":{"name":"нет......so on.
Are there any solutions for this issue?
You need to break the bi-directional relationship between your entity before converting to JSON.
I think there are two options:
Iterate the child collection, e.g. citys in Region and set Region to null. This way, circular dependency would be broken. You my want to add one name mapped attribute regionId in the City so that relational info is still available.
Create another set of POJO objects without circular dependency, copy the values from Entity Objects and then get the JSON using POJO objects.

Categories

Resources