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.
Related
I have a problem using JPA.
I want to the fatherId and father coexistence,When I query with join table.
#Entity
public class Son {
#Id
#Column(name = "id")
private String id;
#Column(name = "father_id")
private String fatherId;
#OneToOne
#JoinColumn(name = "father_id")
private Father father;
}
You have to set one to read-only.
For example:
#Column(name = "father_id", insertable = false, updatable = false)
private String fatherId;
#OneToOne
#JoinColumn(name = "father_id")
private Father father;
Otherwise Hibernate has two ways to write the foreign key.
I am facing a weird issue where even though all fields are set in the java object, when I save the object hibernate tries to insert null values in the fields.
When I further debugged, I saw that while merging the new entity at this line hibernate generates an empty object and sets to the target instead of setting given entity to the target. This results in insert query with null values.
Am I missing some configuration here? Below are the example entities having associations similar to my case.
class Vehicle {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column(nullable = false)
#Enumerated(EnumType.STRING)
#EqualsAndHashCode.Include
private VehicleType vehicleType;
#OneToOne(mappedBy="vehicle", fetch=FetchType.LAZY)
private Car car;
#OneToOne(mappedBy="vehicle", fetch=FetchType.LAZY)
private Truck truck;
}
class Car {
#Id
private Integer id;
#OneToOne(fetch = FetchType.LAZY, optional = false)
#MapsId
#JoinColumn(name = "vehicle_id")
private Vehicle vehicle;
...
}
class Truck {
#Id
private Integer id;
#OneToOne(fetch = FetchType.LAZY, optional = false)
#MapsId
#JoinColumn(name = "vehicle_id")
private Vehicle vehicle;
...
}
I encountered the same problem, in my case I have an application with:
public class Claim extends BaseEntity<Integer> implements Serializable {
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "claimdetailsid", referencedColumnName = "id")
private ClaimDetails claimDetails;
#OneToOne(cascade = CascadeType.PERSIST)
#JoinColumn(name = "beneficiaryid", referencedColumnName = "id")
private Beneficiary beneficiary;
....
}
When I saved the Claim entity, the Claim and ClaimDetails objects were inserted correctly. The other entities had all the fields null, except the id and the creation date.
I tried changing CascadeType.PERSIST to CascadeType.ALL, that solved my insert problem.
But the delete cascade doesn't work now.
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
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.
I am trying to solve a problem regarding category with child categories and parent category on same entity. My database is already set and I can't change it. So, I have mapped my entity this way:
public class Category implements Serializable {
private static final long serialVersionUID = -3432724244623524272L;
#Id
#Column(name = "id")
private Long id;
#Column(name = "key", nullable = false)
private String key;
#Column(name = "category_name", nullable = false)
private String name;
#Column(name = "description")
private String description;
#ManyToOne(targetEntity = Category.class, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "parent_key", referencedColumnName = "key")
private Category parentCategory;
#OneToMany(mappedBy = "parentCategory", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List<Category> childCategories;
//getters and setters ommited
}
Note, that the child categories and parent category is not mapped using the ID attribute, but the "key" attribute. This "key" is not a FK. When JPA is trying to get the data, my application crash. But this crash is look like an infinite loop. No exception is thrown.
What am I doing wrong?
Possible infinite loop :
You load an object A
This object has a child B, which is loaded as well since you use FetchType.EAGER
B has a parent, which is A, which is loaded again
etc.
Try using FetchType.LAZY.