Parent Class:
public class Article implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
#Email
#NotNull
#Column(name = "email")
String email;
#Column(name = "title")
String title;
#Column(name = "published")
Boolean published;
#OneToMany(mappedBy = "article", cascade = {CascadeType.REMOVE}, orphanRemoval = true)
private Set<Comment> comments = new HashSet<>();
// setters and getters
}
Child Class:
public class Comment implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
Long id;
#Email
#NotNull
#Column(name = "email")
String email;
#JsonIgnore
#ManyToOne
#JoinColumn(name = "article_id", referencedColumnName = "id")
Article article;
// setters and getters
}
what i want to do is when deleting article for example with id = "1" it should delete all of its comments automatically ... so how to do that with annotations ??
in other words
for example when make delete request on postman on http://localhost:8080/articles/1 where 1 is article id to delete ... it should delete all of its comments aswell
Just Add OneToMany relation from Article to the Comment:
#OneToMany(mappedBy = "article", orphanRemoval = true)
private Set<Comment> comments = new HashSet<>();
Cascading REMOVE operations from the parent to the child require a relation from the parent to the child.
Update: Added orphanRemoval = true
You shoud create other side of relationship is Article which is:
#OneToMany(cascade=CascadeType.All)
#JoinColumn(name="article_id")
List<Comment> comments
So with this relationship if you delete one Article all its comments will delete.
Related
Currently I have the following 2 entities with a one to many relationship -
#Data
#Entity
#Table(name = "invoice_line")
#IdClass(InvoiceLinePK.class)
public class InvoiceLineEntity {
#Id
#Column(name = "line_id")
private String lineId;
#Id
#Column(name = "client_id")
private Integer clientId;
#Id
#Column(name = "invoice_id")
private String invoiceId;
#Column(name = "item_id")
private String itemId;
#Column(name = "amount")
private BigDecimal amount;
#ManyToOne
private InvoiceEntity invoice;
}
#Entity
#Table(name = "invoice")
#IdClass(InvoicePK.class)
#Data
public class InvoiceEntity {
#Id
#Column(name = "client_id")
private Integer clientId;
#Id
#Column(name = "invoice_id")
private String invoiceId;
#Column(name = "description")
private String description;
#Column(name = "txn_total_amount")
private BigDecimal txnTotalAmount;
#Column(name = "created_time", updatable = false)
#CreationTimestamp
private Date createdTime;
#Column(name = "updated_time")
#UpdateTimestamp
private Date updatedTime;
#OneToMany(fetch = FetchType.EAGER, orphanRemoval = true, mappedBy = "invoice")
private List<InvoiceLineEntity> invoiceLines;
}
In a case wherein let's say, one of my existing invoice has 3 lines and I receive a request that this particular invoice has been updated and it now has only 1 line instead of the previous 3 (so the other 2 have to be deleted), I would like to create a new Invoice object with this 1 InvoiceLineEntity and then do a invoiceRepository.save(invoice)
I am expecting that the other 2 InvoiceLine records would be automatically deleted because the orphanRemoval flag is enabled.
Can someone tell me how I can achieve this relationship by tweaking the entity relationship structure of the above 2 entities?
Your child entity must be the owner of the relationship, so that the orphans are allowed to be deleted
If you change and add mappedBy to that relation
#OneToMany(fetch = FetchType.EAGER, orphanRemoval = true, mappedBy = "bill")
private List<BillLine> billLines;
Then the BillLine must also hold a reference
public class BillLine {
#Id
#Column(name = "line_id")
private String lineId;
#Id
#Column(name = "company_id")
private Integer companyId;
#Id
#Column(name = "bill_id")
private String billId;
#Column(name = "item_id")
private String itemId;
#Column(name = "amount")
private BigDecimal amount;
#ManyToOne
private Bill bill;
}
Now it will remove the orphans
Also since you have multiple #Id on each entity. Do you know that you have to either declare a composite class or an embeddable class? Without one of those the multiple Ids are not valid.
Edit:
1) My bad mappedBy should be placed inside #OneToMany and not #JoinColumn. I have corrected it in my answer
2) Remove #JoinColumn. It is wrong in your configuration. By default #OneToMany inserts a column in the side of the #ManyToOne which holds the references to the primary table. You can override those default configurations and create a separate table for mappings but then you need the #JoinTable and I don't see any reason for that here.
This here
#JoinColumns(value = { #JoinColumn(name = "company_id", referencedColumnName = "company_id"),
#JoinColumn(name = "bill_id", referencedColumnName = "bill_id") })
definitely does not belong on #OneToMany
The following can be applied to #OneToMany but as said before I don't see any reason to do that and complicate a simple mapping which does not require a separate table.
#JoinTable(joinColumns = #JoinColumn(name = "company_id", referencedColumnName = "company_id"),
inverseJoinColumns = #JoinColumn(name = "bill_id", referencedColumnName = "bill_id") )
Check here for more information Jpa primary key
I have a case with Many to Many relationship
Following is the Book class with isbn as unique identifier
#Entity
#Table(name = "book")
public class Book implements Serializable {
private static final long serialVersionUID = -4643154384069203197L;
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(name = "isbn")
private String isbn;
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name = "book_author",
joinColumns = { #JoinColumn(name = "bookId", referencedColumnName = "id") },
inverseJoinColumns = { #JoinColumn(name = "authorId", referencedColumnName = "id") })
private Set<Author> authors = new HashSet<>();
// Getters and setters
// hashcode and equals using only isbn
Following is the Author class with email as unique identifier
#Entity
#Table(name = "author")
public class Author implements Serializable{
private static final long serialVersionUID = -6907306347041383886L;
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(name = "email")
private String email;
#Column(name = "book")
#ManyToMany(mappedBy = "authors")
private Set<Book> books = new HashSet<>();
//getters and setters
// hashcode and equals using only "email"
I am able to achieve unique Book, as the Set checks the isbn and removes all the duplicates.
Since every Book can have many authors and vice versa I tried with Many to Many rekationship.
The problem comes with the unique email, Every book has an individual authors Set. How can I achevie author with unique email in the author table?
Help would be appreciated. Thanks in Advance
Change you #Column(name="email") into #Column(unique = true)
name="email"is redundant since by default it will grab the name of the attribute which is anyways email
#OneToMany side of the relation populates well but the #ManyToOne side overrides each time(only the last item persists)
#Entity
#Table(name="order")
public class Order {
#Id
#Column(name ="orderId")
private String orderId;
#OneToMany(targetEntity = Items.class,
fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "orderId")
#NotNull
private Set<Items> items;
.......
}
#Entity
public class Items {
#Id
private String itemId;
#ManyToOne
#JoinColumn(name="orderId",referencedColumnName = "orderId")
private Order order;
............
}
#Entity
#Table(name="order")
public class Order {
#Id
#Column(name ="orderId")
private String orderId;
#OneToMany(targetEntity = Items.class,
fetch = FetchType.EAGER, cascade = CascadeType.ALL
,mappedBy = "item_id")
#NotNull
private Set<Items> items;
.......
}
#Entity
public class Items {
#Id
private String itemId;
#ManyToOne
#JoinColumn(name="orderId",referencedColumnName = "orderId")
private Order order;
............
Replace targetEntity = Items.class by mappedBy = "order"
and remove referencedColumnName = "orderId" and #JoinColumn(name = "orderId") from OneToMany.
Also if you really need eager fetching delete it from OneToMany side - ManyToOne is eager by default.
I have an issue with a delete to a Many side of a ManyToOne relationship. I've already removed all CascadeTypes from the relationship but the issue still remains. The entry won't be removed (only selects are executed and no delete query). I'm trying to delete it through a CRUD repository call to delete. It calls the method and executes successfully but nothing happens.
The relationship goes as follows: an Activity has an assigned Course, a course can have many activities assigned to it. An Activity has a specific ActivityType.
The classes are as below.
Activity
public class Activity implements Item, Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
...
#ManyToOne
#JoinColumn(name = "type_id", nullable = false)
private ActivityType type;
#ManyToOne
#JoinColumn(name = "course_id", nullable = false)
#JsonSerialize(using = CustomCourseSerializer.class)
private Course course;
...
}
Course
public class Course implements Item, Serializable {
...
#OneToMany(mappedBy = "course", fetch = FetchType.EAGER, targetEntity = Activity.class) //cascade = { CascadeType.MERGE, CascadeType.REFRESH, CascadeType.DETACH, CascadeType.REMOVE}
#Fetch(value = FetchMode.SUBSELECT)
private List<Activity> activities;
...
}
Activity Type (has no reference to Activity)
public class ActivityType implements Item, Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "name", nullable = false, unique = true)
private String name;
...
}
Any ideas how can I solve this issue or at least debug it? Thank you.
Add orphanRemoval = true attribute in the #OneToMany annotation in your Course entity.
public class Course implements Item, Serializable {
...
#OneToMany(mappedBy = "course", fetch = FetchType.EAGER, targetEntity = Activity.class, orphanRemoval = true, cascade = CascadeType.REMOVE )
#Fetch(value = FetchMode.SUBSELECT)
private List<Activity> activities;
...
}
Try to delete reference to Activity from Course. It seems unnecessary to me
I'm italian and i apologize for my english.
I have two POJO classes that rappresents a parent and a child table in my Db.
Parent. Persona.java
#Id #GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "nome", length = 30, nullable = false)
private String nome;
#Column(name = "cognome", length = 30, nullable = false)
private String cognome;
#Column(name = "eta")
private int eta;
#OneToMany(cascade = {CascadeType.PERSIST, CascadeType.REFRESH}, mappedBy = "persona", orphanRemoval = false)
#Column(nullable = true)
private List<Telefono> numeriDiTelefono;
// Others getters and setters
Child. Telefono.java
#Id
#Column(name = "numero_telefono")
private String numeroDiTelefono;
#Column(name = "tipo")
private String tipo;
#ManyToOne(cascade = {CascadeType.REMOVE, CascadeType.PERSIST })
#JoinColumn(name = "persona_id", nullable = true)
private Persona persona;
// Others getters and setters
I have used annotations for mapping those classes in database.
When i try to delete a Persona from the database, hibernate delete the associated Telefono with that Persona, I don't want it.
I would that the child references to has a null value in the field persona_id in the Telefono table, how to obtaining that results? What annotations shoulds I used?
Thanks for everyone.
JPA is not magic.
As #Andy Dufresne suggested, remove the CascadeType.REMOVE annotation. Then you have to set Persona to null in the Telefono, and clear the Telefono collection of the Persona before removing the Persona from the persistence context. So you have to remove all associations.
You can even combine this with the #PreRemove annotation.