I try to audit an entity but I don't want to audit its relationships. If I put #Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED) in #ManyToOne relations, this works and I don't have any exception, but when I try to use the same annotation in a #onetomany with the param mappedby defined, I have an exception that says me that I have to audit the other entity.
Example:
#Table(name = "OWNERS")
#Entity
#EntityListeners(AuditingEntityListener.class)
#Audited
public class Owner {
...
#Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
#ManyToOne(fetch=FetchType.LAZY)
private User user;
...
#Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
#OneToMany(cascade = CascadeType.ALL, mappedBy = "owner" )
private Set<Pet> pets = new HashSet<Pet>();
...
}
When you use #Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED) you are telling hibernate not to audit this entity but audit the relation so you hibernate will save the id of the referenced entity. Thats why Pet must be an #Audited entity.
If you do not want to store the relation at all you need to use #NotAudited
Check this Whats the difference between #NotAudited and RelationTargetAuditMode.NOT_AUDITED in Hibernate EnVers?
Well, I think you have two options here:
Actually audit the entity Pet, if applicable;
Use the annotation #NotAudited instead of #Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED). Think about it, The audit table for Owner doesn't have to persist the Pet's associated. If it does, use option 1.
Hope it helps!
Related
I have table A and table B, table B have a fk that rererences to table A.
class EntityA
#Entity
#Table(name = "tableA")
public class EntityA {
... ... ...
#OneToMany(mappedBy="entityA")
private Set<EntityB> entityBList;
}
class EntityB
#Entity
#Table(name = "tableB")
public class EntityB{
... ... ...
#ManyToOne
#JoinColumn(name="id_entityA", nullable=false)
private EntityA entityA;
}
But when i try to call findAll method from repository (from EntityA) i get:
Could not write JSON: Infinite recursion
This is circular dependency issue you are facing.
Use the #JsonManagedReference and #JsonBackReference annotations to fix this issue.
Refer https://stackoverflow.com/a/47715121/6572971 for how to use this.
I've solved the problem using unidirectional relationship. Used this on my EntityA and erase the property entityA on EntityB.
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "id_nfs")
private Set<EntityB> entityBList
The #JsonManagedReference and #JsonBackReference annotations didnt fix my problem, probably i used wrong.
I have two entities, related as below
#Entity
#Table(name = "APPOINTMENT")
public class Appointment {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long codeAp;
#ManyToOne(fetch = FetchType.EAGER)
, #OnDelete(action = OnDeleteAction.CASCADE)
#JoinColumn(name = "codeP")
private Patient patient;
//attributes
//getters and setters
//constructors
#Entity
#Table(name = "PATIENT")
public class Patient {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long codeP;
//attributes
//getters and setters
//constructors
I'm using JpaRepository delete method.
There is a constraint between the tables PATIENT and APPOINTMENT in database,
I want to remove orphans, when I remove Patient.
I added #OnDelete hibernate annotation but it doesn't work for me!
Can you please tell me why?
I want to keep that unidirectional relationship, can you please help me in this?
If you want to keep using the association as unidirectional only, you can define the lazy-loaded inverse side in a field without exposing getters and setters for it:
#Entity
public class Patient {
#OneToMany(mappedBy = "patient", orphanRemoval = true)
private Collection<Appointment> appointments;
}
This way orphanRemoval logic is applied from patients to their appointments and as a bonus you get the ability to navigate from patients to appointments in HQL queries.
Notice the mappedBy attribute which tells that appointments are responsible for the association management, so you continue to associate appointments with patients by setting patients in the many-to-one relation defined in the Appointment.
There is no way that you could achieve that automatic behavior on the #ManyToOne side. Its just semantically incorrect, period.
Taking under consideration though, the fact that you only want to have an uni-directional mapping and do not specify the Set<Appointment> dependency on the Patient, then a kind of workaround to your situation would be to replace the #ManyToOne with a #OneToOne relationship. Then you would be able to use orphan-removal functionality:
#OneToOne(fetch = FetchType.EAGER, orphanRemoval=true)
#JoinColumn(name = "codeP")
private Patient patient;
Keep in mind though that if you follow this path, adapt you code and at some point you will be in need to introduce #OneToMany dependency on the `Patient' side then you will stumble upon problems. So i would recommend working out pros and cons first in relation to future possible alteration to the entity graph.
I have a concrete class for Employee entity. Employee is persisted by other application, I'm just using the data. I want to extend Employee to add properties that are other Entities using composition. I don't need to persist a child entity per se, but only the entities I'm trying to extend to Employee with using composition. Here is some code to help clear things up.
#Entity
#Table(name = "Legacy_Table_Name", schema = "another_owner")
#Inheritance(strategy = InheritanceType.JOINED)
#DiscriminatorColumn(name = "emp_id")
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private String emp_id;
private String firstName;
etc...
-
public class EnhancedEmployee extends Employee implements Serializable {
private static final long serialVersionUID = 1L;
#Transient
private SomeEntity someCompositionProperty;
#OneToMany(mappedBy = "employee", fetch = FetchType.EAGER, cascade=CascadeType.ALL)
private Collection<AnotherEntityWithItsOwnTable1> list1;
#OneToMany(mappedBy = "employee", fetch = FetchType.EAGER, cascade=CascadeType.ALL)
private Collection<AnotherEntityWithItsOwnTable2> list2;
If I make EnhancedEmployee an entity then JPA tries to create/use an EnhancedEmployee database table (right now in dev so I'm using create-drop persistence.xml property). If I remove the #Entity annotation from EnhancedEmployee, JPA complains that EnhancedEmployee is not an Entity in other classes where I want to utilize these extra properties
#ManyToMany(cascade = CascadeType.MERGE)
#LazyCollection(LazyCollectionOption.FALSE)
#JoinTable(name = "PARTICIPATING_EMPLOYEES", joinColumns = { #JoinColumn(name = "event_id") }, inverseJoinColumns = { #JoinColumn(name = "emp_id") })
private Collection<EnhancedEmployee > participants;
All I'm trying to do is reference an Employee setter getters for these extra properties whether or not they have data persisted for these extra properties.
I realize I could probably just modify my Employee class and add someCompositionProperty and list1/2 relations to that class but doesn't that then violate https://en.wikipedia.org/wiki/Open/closed_principle. While my Employee entity class is the "same" for all my projects the source code is really part of each project's package so perhaps the open/closed doesn't apply here and I should just modify the Employee entity class
If I make EnhancedEmployee an entity then JPA tries to create/use an
EnhancedEmployee database table (right now in dev so I'm using
create-drop persistence.xml property).
You could avoid this by changing the inheritance type to SINGLE_TABLE
Also your discriminator column emp_id seems to me like a bad choice. Better change it to something like #DiscriminatorColumn(name = "TYPE") because emp_id is the primary key and and cannot repeat itself in a table. Also your EnhancedEmployee needs #DiscriminatorValue(value = "ENHANCED")
Let's imagine the scenario: Entity Company and Entity Address has one-to-many bidirectional relationship. So Entity Address will look like:
#Entity
#Table(name = "address")
public class AddressHbm{
#Id
#GeneratedValue(generator = "id-generator")
#Column(name="address_id")
private long id;
#ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE} )
#Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
#JoinColumn(name="company_id")
private Company company = null;
#Column(name="address_name")
private String name;
// other properties and methods
}
I'm going to migrate these codes to Hibernate 4.3 where CascadeType.DELETE_ORPHAN is deprecated. When I am trying to replace CascadeType.DELETE_ORPHAN with orphanRemoval = true, it seems that orphanRemoval = true doesn't even exist in #ManyToOne.
So my question is:
Does AddressHbm use #Cascade(CascadeType.DELETE_ORPHAN) in #ManayToOne incorrectly?
If #Cascade(CascadeType.DELETE_ORPHAN) is misused here, is it valid to just remove it?
I am trying to set a ManyToMany annotation on my code:
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#Table(name = "user")
public class User extends AbstractUser
{
#ManyToMany(mappedBy = "promotors", cascade = CascadeType.PERSIST)
#JoinTable(name = "user_student",
joinColumns=#JoinColumn(name="promotor_id", referencedColumnName="id"),
inverseJoinColumns=#JoinColumn(name="student_id", referencedColumnName="id")
)
private Collection<User> students;
#ManyToMany
private Collection<User> promotors;
}
However every time i try to run the application and the db gets generated, it creates 2 tables for the ManyToMany, 1 new table that is called user_student as i defined beneath, but it also creates a second table user_user which i didn't define but is generated from the promotors.
It's correct you cannot map many to many relationship on one table. As you have only one possible column to map it to. What enforces one to one relationship.
You always have to have mapping table. Its also most convenient way to map many to many relationships on different tables.
Apparently, i didn't define the second ManyToMany correctly, this is the correct code:
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#Table(name = "user")
public class User extends AbstractUser
{
#ManyToMany
#JoinTable(name = "user_student",
joinColumns={#JoinColumn(name="promotor_id", referencedColumnName="id")},
inverseJoinColumns={#JoinColumn(name="student_id", referencedColumnName="id")}
)
private Collection<User> students;
#ManyToMany(mappedBy = "students", cascade = CascadeType.PERSIST)
private Collection<User> promotors;
}