I am having alot of issues trying to delete child records using JPA. Consider the mappings below. I am trying to delete all the state data in the jobs table. When it is removed it will cascade all deletes down the chain. Here is the chain:
Job -> State -> TaskState -> Step
When I try to remove state from job table it is set to NULL. However it is not cascaded down the chain. How would I go about achieving this?
Here is how I am deleting the data:
#Transactional
public void runJob(Long id) throws IOException, JAXBException {
Job job = jobRepository.findOne(id);
if(job.getState() != null){
State stateObj = stateRepository.findOne(job.getState().getId());
stateObj.setTasks(null);
stateRepository.delete(stateObj);
}
job.setState(null);
jobRepository.save(job);
}
Jobs:
#Entity
#Table(name = "jobs")
public class Job implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "name")
private String name;
#Column(name = "description")
private String description;
#Temporal(TemporalType.TIMESTAMP)
private Date date;
#OneToOne
private Image image;
#OneToOne(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
private State state;
#OneToMany
private List<Task> tasks;
#Column(name = "status")
#Enumerated(EnumType.STRING)
private JobStatusEnum status;
#ManyToMany
private List<Device> devices;
#OneToMany
private List<JobRun> runs;
#OneToMany
private List<Container> containers;
public Job() {
this.image = new Image();
this.status = JobStatusEnum.New;
this.devices = new ArrayList<>();
this.runs = new ArrayList<>();
this.containers = new ArrayList<>();
}
public Job(String name, String description, Date date, Image image, State state, List<Task> tasks, JobStatusEnum status, List<Device> devices, List<JobRun> runs, List<Container> containers) {
this.name = name;
this.description = description;
this.date = date;
this.image = image;
this.state = state;
this.tasks = tasks;
this.status = status;
this.devices = devices;
this.runs = runs;
this.containers = containers;
}
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 String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public Image getImage() {
return image;
}
public void setImage(Image image) {
this.image = image;
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
public List<Task> getTasks() {
return tasks;
}
public void setTasks(List<Task> tasks) {
this.tasks = tasks;
}
public JobStatusEnum getStatus() {
return status;
}
public void setStatus(JobStatusEnum status) {
this.status = status;
}
public List<Device> getDevices() {
return devices;
}
public void setDevices(List<Device> devices) {
this.devices = devices;
}
public List<JobRun> getRuns() {
return runs;
}
public void setRuns(List<JobRun> runs) {
this.runs = runs;
}
public List<Container> getContainers() {
return containers;
}
public void setContainers(List<Container> containers) {
this.containers = containers;
}
}
State:
#Entity
#Table(name = "state")
public class State implements Serializable {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name="name")
private String name;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private List<TaskState> tasks;
public State() {
tasks = new ArrayList<>();
}
public State(Long id, String name, List<TaskState> tasks) {
this.id = id;
this.name = name;
this.tasks = tasks;
}
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 List<TaskState> getTasks() {
return tasks;
}
public void setTasks(List<TaskState> tasks) {
this.tasks = tasks;
}
}
TaskState:
#Entity
#Table(name = "task_state")
public class TaskState implements Serializable {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "parent")
private Long parent;
#Column(name = "referenceid")
private Long referenceId;
#Column(name = "name")
private String name;
#Column(name = "status")
private TaskStatusEnum status;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private List<Step> steps;
#Column(name = "maxAttempts")
private Integer maxAttempts;
#ManyToOne
#JsonIgnore
private State state;
public TaskState() {
status = TaskStatusEnum.New;
steps = new ArrayList<>();
maxAttempts = 5;
}
public TaskState(Long id, Long parent, Long referenceId, String name, TaskStatusEnum status, List<Step> steps, Integer maxAttempts) {
this();
this.id = id;
this.parent = parent;
this.referenceId = referenceId;
this.name = name;
this.status = status;
this.steps = steps;
this.maxAttempts = maxAttempts;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getParent() {
return parent;
}
public void setParent(Long parent) {
this.parent = parent;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public TaskStatusEnum getStatus() {
return status;
}
public void setStatus(TaskStatusEnum status) {
this.status = status;
}
public List<Step> getSteps() {
return steps;
}
public void setSteps(List<Step> steps) {
this.steps = steps;
}
public Long getReferenceId() {
return referenceId;
}
public void setReferenceId(Long referenceId) {
this.referenceId = referenceId;
}
public Integer getMaxAttempts() {
return maxAttempts;
}
public void setMaxAttempts(Integer maxAttempts) {
this.maxAttempts = maxAttempts;
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
}
Step:
#Entity
#Table(name = "step")
public class Step implements Serializable {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "name")
private String name;
#Column(name = "groupname")
private String group;
#Column(name = "route")
private String route;
#Column(name = "celerytask")
private String celeryTask;
#Column(name = "postbackqueuename")
private String postBackQueueName;
#Column(name = "postbackerrorqueuename")
private String postBackErrorQueueName;
#Enumerated(EnumType.STRING)
#Column(name = "status")
private TaskStatusEnum status;
#ElementCollection
private List<String> arguements;
#Column(name="runningTaskId")
private Long runningTaskId;
#Column(name="result")
private String result;
#Column(name="attempt")
private Integer attempt;
#JsonIgnore
#ManyToOne
private TaskState task;
public Step() {
arguements = new ArrayList<>();
status = TaskStatusEnum.New;
attempt = 0;
}
public Step(String name, String group, String route, String celeryTask, String postBackQueueName, String postBackErrorQueueName, TaskStatusEnum status, List<String> arguements, Long runningTaskId) {
this();
this.name = name;
this.group = group;
this.route = route;
this.celeryTask = celeryTask;
this.postBackQueueName = postBackQueueName;
this.postBackErrorQueueName = postBackErrorQueueName;
this.status = status;
this.arguements = arguements;
this.runningTaskId = runningTaskId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGroup() {
return group;
}
public void setGroup(String group) {
this.group = group;
}
public String getRoute() {
return route;
}
public void setRoute(String route) {
this.route = route;
}
public String getCeleryTask() {
return celeryTask;
}
public void setCeleryTask(String celeryTask) {
this.celeryTask = celeryTask;
}
public String getPostBackQueueName() {
return postBackQueueName;
}
public void setPostBackQueueName(String postBackQueueName) {
this.postBackQueueName = postBackQueueName;
}
public String getPostBackErrorQueueName() {
return postBackErrorQueueName;
}
public void setPostBackErrorQueueName(String postBackErrorQueueName) {
this.postBackErrorQueueName = postBackErrorQueueName;
}
public List<String> getArguements() {
return arguements;
}
public void setArguements(List<String> arguements) {
this.arguements = arguements;
}
public TaskStatusEnum getStatus() {
return status;
}
public void setStatus(TaskStatusEnum status) {
this.status = status;
}
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
public Integer getAttempt() {
return attempt;
}
public void setAttempt(Integer attempt) {
this.attempt = attempt;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getRunningTaskId() {
return runningTaskId;
}
public void setRunningTaskId(Long runningTaskId) {
this.runningTaskId = runningTaskId;
}
public TaskState getTask() {
return task;
}
public void setTask(TaskState task) {
this.task = task;
}
}
It's not cascading because of stateObj.setTasks(null);.
You're breaking the link between the State and its Tasks so when you're deleting the State, the delete doesn't cascade on anything.
Related
I'm working on Calorie Counter Application. After logging in, each user will only have access to their meals.
I have a database like below:
I'll display all information like the template below.
Meal 1
Chicken breast
100g
130kcal
Apple
200g
100kcal
Tomatoes
300g
30kcal
Meal 2
Chicken breast
100g
130kcal
Apple
200g
100kcal
Tomatoes
300g
30kcal
User class:
#Entity
#Table(name = "users")
public class User {
private int id;
private String username;
private String password;
private int age;
private String email;
private Gender gender;
private List<Meal> meals;
public User() {
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#Column(name = "username")
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
#Column(name = "password")
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
#Column(name = "age")
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
#Column(name = "email")
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
#Column(name = "gender")
public Gender getGender() {
return gender;
}
public void setGender(Gender gender) {
this.gender = gender;
}
#OneToMany(mappedBy = "user")
public List<Meal> getMeals() {
return meals;
}
public void setMeals(List<Meal> meals) {
this.meals = meals;
}
private enum Gender{
MALE,
FEMALE
}
}
Meal class:
#Entity
#Table(name = "meals")
public class Meal {
private int id;
private LocalDate date = LocalDate.now();
private User user;
private List<MealFoodProduct> mealFoodProducts;
public Meal() {
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#OneToMany(mappedBy = "foodProduct")
public List<MealFoodProduct> getMealFoodProducts() {
return mealFoodProducts;
}
public void setMealFoodProducts(List<MealFoodProduct> mealFoodProducts) {
this.mealFoodProducts = mealFoodProducts;
}
#Column(name = "created_at")
public LocalDate getDate() {
return date;
}
public void setDate(LocalDate date) {
this.date = date;
}
#ManyToOne
#JoinColumn(name = "user_id")
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
FoodProduct class:
#Entity
#Table(name = "food_products")
public class FoodProduct {
private int id;
private String productName;
private Double proteins;
private Double fats;
private Double carbohydrates;
private Double calories;
public FoodProduct() {
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#Column(name = "product_name")
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
#Column(name = "proteins")
public Double getProteins() {
return proteins;
}
public void setProteins(Double proteins) {
this.proteins = proteins;
}
#Column(name = "fats")
public Double getFats() {
return fats;
}
public void setFats(Double fats) {
this.fats = fats;
}
#Column(name = "carbohydrates")
public Double getCarbohydrates() {
return carbohydrates;
}
public void setCarbohydrates(Double carbohydrates) {
this.carbohydrates = carbohydrates;
}
#Override
public String toString() {
return productName;
}
#Column(name = "calories")
public Double getCalories() {
return calories;
}
public void setCalories(Double calories) {
this.calories = calories;
}
}
MealFoodProcuct class
#Entity
#Table(name = "meals_food_products")
public class MealFoodProduct {
private Meal meal;
private FoodProduct foodProduct;
private double weight;
public MealFoodProduct() {
}
#ManyToOne
#JoinColumn(name = "meal_id")
public Meal getMeal() {
return meal;
}
public void setMeal(Meal meal) {
this.meal = meal;
}
#ManyToOne
#JoinColumn(name = "food_product_id")
public FoodProduct getFoodProduct() {
return foodProduct;
}
public void setFoodProduct(FoodProduct foodProduct) {
this.foodProduct = foodProduct;
}
#Column(name = "food_product_weight")
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
}
My questions:
Is it correct way to connect these classes?
What should be an ID in MealFoodProduct class?
I would suggest you to use composite identifiers with #IdClass for the MealFoodProduct entity.
#Entity
#Table(name = "meals_food_products")
#IdClass( MealFoodProductPK.class )
public class MealFoodProduct {
#Id
#ManyToOne
#JoinColumn(name = "meal_id")
public Meal getMeal() {
return meal;
}
#Id
#ManyToOne
#JoinColumn(name = "food_product_id")
public FoodProduct getFoodProduct() {
return foodProduct;
}
// ...
}
public class MealFoodProductPK implements Serializable {
private Meal meal;
private FoodProduct foodProduct;
public MealFoodProductPK(Meal meal, FoodProduct foodProduct) {
this.meal = meal;
this.foodProduct = foodProduct;
}
public MealFoodProductPK() {
}
//Getters, setters, equals, hashCode are omitted for brevity
}
Additional details see here.
P.S. Other parts of your mapping look good.
professionals!
I have a question. What is a better idea to connect 2 tables in spring boot via ID? As an example: we have 2 tables client and books. Each client can borrow a book and the status of book will be changed.
I know how to make it in DB using SQL. But the question is, how to do this in jpa/hibernate.
I have an error of ManyToMany or OneToMany.....
#Entity
public class Book implements java.io.Serializable {
private static final long serialVersionUID = 1L;
#TableGenerator(name = "BOOK_GEN", allocationSize = 1)
#Id
#GeneratedValue(generator = "BOOK_GEN")
private int id;
private String book_name;
private String ISBN;
private String publish_year;
private String publisher;
private Boolean status;
#OneToMany(mappedBy="book" ,cascade=CascadeType.ALL , fetch = FetchType.LAZY)
private Collection<Client> authors =new ArrayList<Client>();
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getBook_name() {
return book_name;
}
public void setBook_name(String book_name) {
this.book_name = book_name;
}
public String getISBN() {
return ISBN;
}
public void setISBN(String iSBN) {
ISBN = iSBN;
}
public String getPublish_year() {
return publish_year;
}
public void setPublish_year(String publish_year) {
this.publish_year = publish_year;
}
public String getPublisher() {
return publisher;
}
public void setPublisher(String publisher) {
this.publisher = publisher;
}
public Boolean getStatus() {
return status;
}
public void setStatus(Boolean status) {
this.status = status;
}
public Collection<Author> getAuthors() {
return authors;
}
public void setClients(Collection<Client> clients) {
this.clients = clients;
}}
#Entity
public class Client implements java.io.Serializable {
private static final long serialVersionUID = 1L;
#TableGenerator(name = "CLT_GEN", allocationSize = 1)
#Id
#GeneratedValue(generator = "CLT_GEN")
private int id;
private Boolean bookedstatus;
private Boolean bookstatus;
#ManyToOne(fetch = FetchType.LAZY)
private Book book;
private String name ;
private String surname;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Book getBook() {
return book;
}
public void setBook(Book book) {
this.book = book;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
public Boolean getBookedstatus() {
return bookedstatus;
}
public void setBookedstatus(Boolean bookedstatus) {
this.bookedstatus = bookedstatus;
}
public Boolean getBookstatus() {
return bookstatus;
}
public void setBookstatus(Boolean bookstatus) {
this.bookstatus = bookstatus;
}
}
Since you have mentioned "A client can borrow a book", one-to-one mapping should work the best for you. Please refer to the below code. Also you didn't mention the error you are facing with your current implementation.
#Entity
public class Book implements java.io.Serializable {
private static final long serialVersionUID = 1L;
#TableGenerator(name = "BOOK_GEN", allocationSize = 1)
#Id
#GeneratedValue(generator = "BOOK_GEN")
private int id;
private String book_name;
private String ISBN;
private String publish_year;
private String publisher;
private Boolean status;
#OneToOne(fetch = FetchType.LAZY, mappedBy = "book", cascade = CascadeType.ALL)
private Collection<Client> authors;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getBook_name() {
return book_name;
}
public void setBook_name(String book_name) {
this.book_name = book_name;
}
public String getISBN() {
return ISBN;
}
public void setISBN(String iSBN) {
ISBN = iSBN;
}
public String getPublish_year() {
return publish_year;
}
public void setPublish_year(String publish_year) {
this.publish_year = publish_year;
}
public String getPublisher() {
return publisher;
}
public void setPublisher(String publisher) {
this.publisher = publisher;
}
public Boolean getStatus() {
return status;
}
public void setStatus(Boolean status) {
this.status = status;
}
public Collection<Client> getAuthors() {
return authors;
}
public void setAuthors(Collection<Client> authors) {
this.authors = authors;
}
}
#Entity
public class Client implements java.io.Serializable {
private static final long serialVersionUID = 1L;
#TableGenerator(name = "CLT_GEN", allocationSize = 1)
#Id
#GeneratedValue(generator = "CLT_GEN")
private int id;
private Boolean bookedstatus;
private Boolean bookstatus;
#OneToOne(fetch = FetchType.LAZY)
#PrimaryKeyJoinColumn
private Book book;
private String name ;
private String surname;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Book getBook() {
return book;
}
public void setBook(Book book) {
this.book = book;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
public Boolean getBookedstatus() {
return bookedstatus;
}
public void setBookedstatus(Boolean bookedstatus) {
this.bookedstatus = bookedstatus;
}
public Boolean getBookstatus() {
return bookstatus;
}
public void setBookstatus(Boolean bookstatus) {
this.bookstatus = bookstatus;
}
}
I am building an order tracking system in Spring Boot, using Hibernate annotations and Repositories. I have an Order class, which can have a list of OrderItems. These map to a ORDER and ORDER_ITEMS table respectively. The code I have representing the two is below.
Order.java
package net.township.order;
import org.hibernate.annotations.Cascade;
import javax.persistence.*;
import java.util.Date;
import java.util.List;
import java.util.Set;
#Entity
#Table(name = "orders")
public class Order {
public Order() {
}
public Order(long merchantId, String firstDeliveryName, String
lastDeliveryName, String deliveryAddress, String status, Date createDate,
Date updateDate) {
this.merchantId = merchantId;
this.lastDeliveryName = lastDeliveryName;
this.firstDeliveryName = firstDeliveryName;
this.deliveryAddress = deliveryAddress;
this.status = status;
this.createDate = createDate;
this.updateDate = updateDate;
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "order_id", unique = true)
private long orderId;
#Column(name = "merchant_id")
private long merchantId;
#Column(name = "first_delivery_name")
private String firstDeliveryName;
#Column(name = "last_delivery_name")
private String lastDeliveryName;
#Column(name = "delivery_address")
private String deliveryAddress;
#Column
private String status;
#OneToMany(mappedBy = "order", cascade = {
CascadeType.ALL,CascadeType.PERSIST,CascadeType.MERGE })
private List<OrderItem> orderItems;
#Column(name = "create_date")
private Date createDate;
#Column(name = "update_date")
private Date updateDate;
public void setOrderId(long orderId) {
this.orderId = orderId;
}
public long getMerchantId() {
return merchantId;
}
public void setMerchantId(long merchantId) {
this.merchantId = merchantId;
}
public List<OrderItem> getOrderItems() {
return orderItems;
}
public void setOrderItems(List<OrderItem> orderItems) {
this.orderItems = orderItems;
}
public String getLastDeliveryName() {
return lastDeliveryName;
}
public void setLastDeliveryName(String lastDeliveryName) {
this.lastDeliveryName = lastDeliveryName;
}
public Date getUpdateDate() {
return updateDate;
}
public void setUpdateDate(Date updateDate) {
this.updateDate = updateDate;
}
public Long getOrderId() {
return orderId;
}
public void setOrderId(Long orderId) {
this.orderId = orderId;
}
public String getFirstDeliveryName() {
return firstDeliveryName;
}
public void setFirstDeliveryName(String firstDeliveryName) {
this.firstDeliveryName = firstDeliveryName;
}
public String getDeliveryAddress() {
return deliveryAddress;
}
public void setDeliveryAddress(String deliveryAddress) {
this.deliveryAddress = deliveryAddress;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
}
OrderItem.java
package net.township.order;
import com.fasterxml.jackson.annotation.JsonBackReference;
import org.hibernate.annotations.Cascade;
import javax.persistence.*;
#Entity
#Table(name = "order_items")
public class OrderItem {
#Id
#GeneratedValue
#Column(name = "id")
private Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Order getOrder() {
return order;
}
public void setOrder(Order order) {
this.order = order;
}
#Column
private String name;
#Column
private String description;
#Column
private Long quantity;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn (name="ORDER_ID")
#JsonBackReference
#Cascade(value={org.hibernate.annotations.CascadeType.ALL})
private Order order;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Long getQuantity() {
return quantity;
}
public void setQuantity(Long quantity) {
this.quantity = quantity;
}
}
When I POST a new Order from my front-end, it is mapped to an Order object correctly. All OrderItems that were provided in the JSON are present in the object as a List as well. However, after I save it to the database using my OrderRepository's save method (it's just a CrudRepository), my database contains a new Order object with the correct fields, but nothing is ever created in ORDER_ITEMS.
I've poked around the documentation for both Hibernate and JPA OneToMany annotations, and I don't see where I'm going wrong here. I'll also add that I'm doing no manual schema creation, letting SpringBoot handle setting up everything in H2 for me.
This is what ultimately worked for me.
Order.java
package net.township.order;
import org.hibernate.annotations.Cascade;
import javax.persistence.*;
import java.util.Date;
import java.util.List;
import java.util.Set;
#Entity
#Table(name = "orders")
public class Order {
public Order() {
}
public Order(long merchantId, String firstDeliveryName, String lastDeliveryName, String deliveryAddress, String status, Date createDate, Date updateDate) {
this.merchantId = merchantId;
this.lastDeliveryName = lastDeliveryName;
this.firstDeliveryName = firstDeliveryName;
this.deliveryAddress = deliveryAddress;
this.status = status;
this.createDate = createDate;
this.updateDate = updateDate;
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "order_id", unique = true)
private long orderId;
#Column(name = "merchant_id")
private long merchantId;
#Column(name = "first_delivery_name")
private String firstDeliveryName;
#Column(name = "last_delivery_name")
private String lastDeliveryName;
#Column(name = "delivery_address")
private String deliveryAddress;
#Column
private String status;
#OneToMany( cascade = CascadeType.ALL)
#JoinColumn(name = "order_id", referencedColumnName = "order_id")
private List<OrderItem> orderItems;
#Column(name = "create_date")
private Date createDate;
#Column(name = "update_date")
private Date updateDate;
public void setOrderId(long orderId) {
this.orderId = orderId;
}
public long getMerchantId() {
return merchantId;
}
public void setMerchantId(long merchantId) {
this.merchantId = merchantId;
}
public List<OrderItem> getOrderItems() {
return orderItems;
}
public void setOrderItems(List<OrderItem> orderItems) {
this.orderItems = orderItems;
}
public String getLastDeliveryName() {
return lastDeliveryName;
}
public void setLastDeliveryName(String lastDeliveryName) {
this.lastDeliveryName = lastDeliveryName;
}
public Date getUpdateDate() {
return updateDate;
}
public void setUpdateDate(Date updateDate) {
this.updateDate = updateDate;
}
public Long getOrderId() {
return orderId;
}
public void setOrderId(Long orderId) {
this.orderId = orderId;
}
public String getFirstDeliveryName() {
return firstDeliveryName;
}
public void setFirstDeliveryName(String firstDeliveryName) {
this.firstDeliveryName = firstDeliveryName;
}
public String getDeliveryAddress() {
return deliveryAddress;
}
public void setDeliveryAddress(String deliveryAddress) {
this.deliveryAddress = deliveryAddress;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
}
OrderItem.java
package net.township.order;
import com.fasterxml.jackson.annotation.JsonBackReference;
import javax.persistence.*;
#Entity
#Table(name = "order_items")
public class OrderItem {
#Id
#GeneratedValue
#Column(name = "id")
private Long id;
#Column(name = "order_id")
private Long orderId;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Column
private String name;
#Column
private String description;
#Column
private Long quantity;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Long getQuantity() {
return quantity;
}
public void setQuantity(Long quantity) {
this.quantity = quantity;
}
}
Add CascadeType.ALL to your mapping.
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.
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)