When deleting a parent entity I also want to remove the associated child entities (from the database). I have tried to make use of cascade on remove as seen below but I must be doing something incorrectly.
When calling remove on the parent entity object, I recieve the error message: "The entity is still referenced elsewhere in the database". I can confirm that the only place where the entity is referenced elsewhere in the database is in the two tables below (if I manually delete the child row from the database, the remove call on the parent works fine). I have been reading about entity objects and trying different things for the last 9 hours. What am I doing wrong?
Here is my parent table:
#Entity
#Table(name = "TURTLE_LOOKUP")
public class TurtleLookup implements Serializable
{
#Basic(optional = false)
#Column(name = "TURTLEID")
private int turtleid;
#Basic(optional = false)
#Column(name = "TURTLE")
private String turtle;
#OneToMany(mappedBy = "turtleType", cascade = CascadeType.REMOVE)
List<TurtleReview> turtleReviews;
...
}
Here is my child table:
#Entity
#Table(name = "TURTLE_REVIEW")
public class TurtleReview implements Serializable
{
#Column(name = "TURTLE_REVIEW_ID")
private int turtleReviewId;
#Column(name = "TURTLE_YEAR")
private int turtleYear;
#ManyToOne(cascade = CascadeType.REMOVE, optional = false)
#JoinColumn(name = "TURTLE_ID", referencedColumnName = "TURTLEID")
private TurtleLookup turtleType;
#Column(name = "IS_COMPLETE")
private short isComplete;
...
}
EDIT/UPDATE:
If I change CascadeType.REMOVE to CascadeType.ALL, the TurtleReview entities are successfully deleted from the database when deleting the parent TurtleLookup entity object. However, when calling the below function to create a new TurtleReview entity object, JPA tries to insert a new TurtleLookup entity in to the database, which throws the exception: "Entry already resides within the DB. Transaction rolled back". Below is the code executed when creating a new TurtleReview entity.
public void setDatasetReviewComplete(TurtleLookup turtle, Short year, boolean isComplete)
{
TurtleReview turtleReview = getTurtleReview(turtle, year);
if (turtleReview == null)
{
turtleReview = new TurtleReview();
turtleReview.setTurtleYear(year)
turtleReview.setTurtleType(new a.b.entity.TurtleLookup(turtle.getId(), turtle.getValue()));
}
turtleReview.setIsComplete(isComplete ? (short)1 : 0);
entityManager.persist(turtleReview);
}
try change cascade value to all or all-delete-orphan
#OneToMany(mappedBy = "turtleType", cascade = CascadeType.REMOVE)
List<TurtleReview> turtleReviews;
...
}
There might be an issue with your domain model, a part that is left out in the question. Do you possibly have circular cascades? If you have a circle of cascades and some of them are CascadeType.REMOVE and some are CascadeType.PERSIST, then Hibernate (not sure about other JPA implementation) will just do.... nothing when you call the remove() method. Without an error or exception message.
Try with hibernate #Cascade annotation:
#Cascade(value = CascadeType.ALL)
#OneToOne(mappedBy = "turtleReview") // mappedBy name of TurtleRewiew object field in TurtleLookup entity class
private TurtleLookup turtleType;
If your relationship is oneToOne you can't have oneToMany to the other side and you can't have List<TurtleReview>. If your relationship is oneToMany then your entities will be for example:
#Entity
#Table(name = "TURTLE_LOOKUP")
public class TurtleLookup implements Serializable
{
#Basic(optional = false)
#Column(name = "TURTLEID")
private int turtleid;
#Basic(optional = false)
#Column(name = "TURTLE")
private String turtle;
#OneToMany(mappedBy = "turtleType") // or add cascade = javax.persistence.CascadeType.ALL and remove #Cascade if you are not using hibernate
#Cascade(value = CascadeType.ALL)
List<TurtleReview> turtleReviews;
...
}
#Entity
#Table(name = "TURTLE_REVIEW")
public class TurtleReview implements Serializable
{
#Column(name = "TURTLE_REVIEW_ID")
private int turtleReviewId;
#Column(name = "TURTLE_YEAR")
private int turtleYear;
#ManyToOne
#JoinColumn(name = "TURTLE_ID", referencedColumnName = "TURTLEID")
private TurtleLookup turtleType;
#Column(name = "IS_COMPLETE")
private short isComplete;
...
}
Related
I want to convert the following mapping on courseDetails to manyToMany.
This is because I get an exception Found shared references to a collection: com.xyz.courseDetails and I assume this happens because the relation is not actually one to many in the database, since there are some course_detail tuples that has multiple courses.
#Entity
#Table(name = "courses")
public class Course
{
#Column(name = "course_detail_id")
private Long extendedCourseDetailId;
...
#OneToMany(fetch = FetchType.LAZY, targetEntity = CourseDetail.class, cascade = CascadeType.ALL)
#JoinColumn(name="id", referencedColumnName="course_detail_id")
private List<CourseDetail> courseDetails = new ArrayList<>();
}
Simply changing the annotation to ManyToMany does not work, JPA somehow couldn't find the related columns. Why? How can I do this?
What do you think of this :
Let's assume the entity CourseDetail has as ID :
public class CourseDetail
{
#Id
#Column(name = "cd_id")
private Long courseDetailId;
So this non tested code might help you.
where the table "course__course_detail" will be automatically created to hold the relationship with 2 columns : "course_id" and "coursedetail_id".
#Entity
#Table(name = "courses")
public class Course
{
#Id
#Column(name = "c_id")
private Long courseId;
// #Column(name = "course_detail_id") // I comment because I dont understand the purpose
// private Long extendedCourseDetailId;
...
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "course__course_detail",
joinColumns = #JoinColumn(name = "course_id", referencedColumnName="c_id"),
inverseJoinColumns = #JoinColumn(name = "coursedetail_id", referencedColumnName="cd_id"),
)
private List<CourseDetail> courseDetails = new ArrayList<>();
}
PS: NOT TESTED
Feel free to tell me more in comments.
I am using Spring Boot 2.3.0.
I have a ManyToOne relationship on one side and a OneToMany relationship on the other side. One parent to many children, but many children to one parent. I am trying to be able to delete children without affecting the parent. I have nullable = false on the child side for the parent field because I don't want to end up with accidental nulls for parent in the parent_to_child table. I want things like that to be enforced and get caught.
When I do readerRepository.save(reader) after removing one of the TBRList items (this is the child) from the List<TBRList> in the Reader object (this is the parent), I keep getting an error about the parent field not being able to be null when trying to delete the child. If I set nullable to false on the parent field in the child object, my parent disappears.
I thought I understood how this was supposed to work, but obviously not.
I have:
#Entity //parent
public class Reader implements Serializable {
#Id
#GeneratedValue(strategy = IDENTITY)
#JsonIgnore
private Long id;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "reader", orphanRemoval = true)
Set<TBRList> tbrLists = new HashSet<>();
//other fields, getters, setters, etc.
}
#Entity(name = "tbr") //child
public class TBRList implements Serializable {
#Id
#GeneratedValue(strategy = IDENTITY)
private Long id;
#Column(nullable = false)
private String name;
#JsonIgnore
#ManyToOne
#JoinColumn(name = "reader_id", nullable = false)
private Reader reader;
//other fields, getters, setters, etc
}
In the below snippet, readerRepository.save(reader) is where the org.hibernate.PropertyValueException: not-null property references a null or transient value : com.me.project.entity.TBRList.reader exception is happening.
if (reader.hasTBRList(tbrListName)) {
Iterator<TBRList> it = reader.getTbrLists().iterator();
while (it.hasNext()) {
TBRList tbrList = it.next();
if (tbrList.getName().equals(tbrListName)) {
it.remove();
readerRepository.save(reader);
break;
}
}
}
I tried to also set reader to null in TBRList and delete it via the tbrListRepository, but the same thing happened. In fact, I've tried too many things to remember them all (I try to ask questions as a last result after hours of searching and trying things).
What am I doing wrong with trying to have a Parent/Child relationship, where I don't want Child.parent to be null, and I want to be able to delete a child from the parent without deleting the parent in the process?
I created the same classes and i get this result to execute as you want:
#Entity(name = "tbr")
#Data
public class TBRList {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(nullable = false)
private String name;
#JsonIgnore
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "reader_id", nullable = false)
private Reader reader;
}
#Entity
#Data
public class Reader {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#JsonIgnore
private Long id;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "reader", orphanRemoval = true)
Collection<TBRList> tbrLists ;
}
I am trying to build a bidirectional one to many relationship with the spring data jpa but the list annotated with #onetomany always return one element.
Here is the code for my entities(setters and getters omitted):
#Entity
#Table(name = "sdk_sdk")
public class SDKEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String version;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "sdk")
#OrderBy("order ASC")
private List<SDKFileEntity> fileEntities;
}
And the second entity:
#Entity
#Table(name = "sdk_file")
public class SDKFileEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String fileType;
private Integer sdkId;
public SDKFileEntity() {
}
#ManyToOne
#JoinColumn(name = "id", insertable = false, updatable = false)
private SDKEntity sdk;
I am trying to have a manytoone mapping where the sdkId corresponds to the id from the SDKEntity class.
Whenever I try to get the sdkfiles from the sdkEntity using spring's repository, the size of the list is always 1.
So for example:
SDKEntity entity=repository.findOne(foo);
List<SDKFileEntity> files=entity.getFileEntities();
here the size of files is 1, I have to delete the first element from the database to obtain the second element.
For me the reason here was that a parent entity implemented equals and hashcode
and unfortunately in a way that all existing entities were equal.
And non of the child entities implemented it herself.
So then the #OneToMany relation returned only the first element.
Took me quite some time.
This part of Code looks suspicious
#ManyToOne
#JoinColumn(name = "id", insertable = false, updatable = false)
private SDKEntity sdk;
name = "id" it should be actual column name as written in database column name like this
#JoinColumn(name = "VISIT_ID", referencedColumnName = "ID")
#ManyToOne
private Visit visitId;
First of all, sorry for my English.
So, I'm working with MS SQL Server with hibernate and i faced with a problem.
I have next mapping of one of the tables in my DB:
#Entity(name = " ... ")
public class Entity extends BaseEntity implements Comparable {
#Id
#Column(name = "...")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column(name = "parent_entity_id", insertable = false, updatable = false)
private Integer parentId;
#ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST})
#JoinColumn(name = "parent_entity_id")
private Entity parent;
#OneToMany(mappedBy = "parent", fetch = FetchType.LAZY, cascade = {CascadeType.REMOVE}, orphanRemoval = true)
private Set<Entity> children;
//other fields, setters, getters
}
That means, that my Entity objects can have children, which are also an Entity objects.
So, my problems is that I can't correctly delete parent with all his children. When I try to remove parent, i get an SQL error:
The DELETE statement conflicted with the SAME TABLE REFERENCE
So, any ideas, how to solve this problem?
You have a foreign key defined between parent_entity_id and id. Set it to allow cascading deletes: deleting a parent will delete all it's children, and all their children et cetera.
Be sure you actually want this to happen!
I have a relationship n/n between Product and Order
So I have a third table ProductOrder, because I need new columns when they are created.
public class Order implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ORDER_SEQ")
#Column(unique = true, nullable = false, updatable = false)
private Long idOrder;
#OneToMany(mappedBy = "order", cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
private Set<ProductOrder> productOrder;
//get and setter
here is the ProductOrder:
#Entity
#IdClass(ProductOrderId.class)
public class ProductOrder implements Serializable {
private static final long serialVersionUID = 3943799614725570559L;
#Id
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "product_id")
private Product product;
#Id
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "order_id")
private Order order;
private Integer qtdProduct;
private Double unitValueProductOrder;
//get and setter
also My ProcutOrderId (just in case)
public class ItemCompraId implements Serializable {
private Long compra;
private Long produto;
//get and set
and my Order entity:
#Entity
#SequenceGenerator(name = "ORDER_SEQ", sequenceName = "s_compra", initialValue = 1, allocationSize = 1)
public class Order implements Serializable {
private static final long serialVersionUID = 3943799614725570559L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ORDER_SEQ")
#Column(unique = true, nullable = false, updatable = false)
private Long idOrder;
private Double orderValue;
private Date creatingDate;
#OneToMany(mappedBy = "order", cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
private Set<ProductOrder> productOrder;
So basically I have any Products ALREADY persisted in db... I just got a list of them when some order is about to be ordered. So I wanna persist a new object (Order) based on some already persisted object (products). This is the method invoked on managedbean to persist an Order.
public String doOrder() throws Exception {
try {
Order order = new Order();
compra.setCreatingDate(new Date());
compra.setOrderValue(null);
if (compra.getProductOrder() == null)
compra.setProductOrder(new HashSet<ProductOrder>());
for (Product product : listOfMyCartOfProducts) {
ProductOrder productOrder = new ProductOrder();
productOrder.setQtdProduct(100);
productOrder.unitValueProductOrder(null);
productOrder.setOrder(order);
productOrder.setProduct(product); //I THINK THAT THE PROBLEM IT'S HERE
order.getOrderProduct().add(productOrder);
}
ejbInvoke.persist(order); //tryed .merge and it doesn't work aswell
return "stuff";
Any ideas?
I'm desperate.. I need this working for yesterday..
Any help please??
Btw I'm using JSF 2.0, Hibernate with JPA 2.0 and Postgres.
Regards,
You have set the order->productOrder->product relationships to cascade the persist (included in cascadeType.ALL). When you call persist on order, you are in effect calling persist on ProductOrder and Product as well, which is expected to throw an exception if any of them already exist in the database.
Either
1) remove the cascade persist option on the productOrder->product relationship so that persist is not getting called - with the draw back that you will have to manually call persist if you ever associate new Products through a new Order.
2) Call em.find using the product pk, and associate the instance returned to the productOrder->product relationship
3) use em.merge instead which will cascade over each relationship and decide on its own if the entity exists or needs to be inserted. This will cause changes made within the product instance though to be merged as well.