How to disable delete for JoinTable? - jpa

I have problem with disable delete for JoinTable.
#Entity
class Employee
{
#Id
Long id;
#ManyToOne( cascade = { CascadeType.REFRESH } )
#JoinTable( name = "Employee2AddressOracleView",
joinColumns = #JoinColumn( name = "employee_id" ),
inverseJoinColumns = #JoinColumn( name = "address_id" )
private Address address;
)
Address for Employee is calculated in View. It works, I can load Employee but when I want delete employee JPA want delete row from view to. It is possible to disable this delete query?
JPA query in console:
delete from Employee where employee_id = ?
delete from Employee2AddressOracleView where employee_id = ?

The accepted answer has a link to hibernate forums which are dead. I managed to pull the link out on archive.org.
The solution is to create a separate entity representing the join table, mapped to the view, instead of using #JoinTable.
Main entity mappings:
#Entity
#Table(name="Main")
public class MainEntity {
#Id
#Column(name="id")
private Integer id;
#OneToOne
#PrimaryKeyJoinColumn
private JoinTableViewEntity joinEntity;
}
Join table view entity mappings:
#Entity
#Table(name="TableView")
public class JoinTableViewEntity {
#Id
#Column(name="id")
private Integer mainEntityId;
#ManyToOne
#JoinColumn(name="other_id", updatable=false, insertable=false)
private OtherEntity other;
}
It also works without updateable and insertable attributes.

If you are using EclipseLink you can use a DescriptorCustomizer to make the mapping readOnly.

Related

JPA join same child table with a differen key

I have situation that the same table is linked two different keys
all names either it manager's name or name of the employee stored in "employee_table" reason is manager is also an employee
manager_link_table
id
manager_id
employee_table
id
name
Now I want two child objects as below
I am trying to create JPA Entity with OneToOne as
#Entity
#Table(name="manager_link_table")
class ManagerLinkTable {
#OneToOne(fetch = FetchType.EAGER)
#JoinColumn( name="id", referencedColumnName="id")
private EmployeeTable employee;
#OneToOne(fetch = FetchType.EAGER)
#JoinColumn( name="id", referencedColumnName="manager_id")
private EmployeeTable manager;
}
#Entity
#Table(name="employee_table")
class EmployeeTable {
private String id;
private String name;
}
I am writing JPA query as
SELECT m FROM ManagerLinkTable m
I want m.employee.name and m.manager.name to be different
But I am getting the same, it seems the referencedColumnName is ignored while joining the table
Does anyone faced this issue ?

ERROR: update or delete on table "tablename" violates foreign key constraint

I'm trying to delete the parent student or parent course and I get this error:
Caused by: org.postgresql.util.PSQLException: ERROR: update or delete on table "student" violates foreign key constraint "fkeyvuofq5vwdylcf78jar3mxol" on table "registration"
RegistrationId class is a composite key used in Registration class. I'm using Spring data jpa and spring boot.
What am I doing wrong? I know that putting cascadetype.all should also remove the children when the parent is deleted but it is giving me an error instead.
#Embeddable
public class RegistrationId implements Serializable {
#JsonIgnoreProperties("notifications")
#OneToOne(cascade=CascadeType.ALL)
#JoinColumn(name = "student_pcn", referencedColumnName="pcn")
private Student student;
#JsonIgnoreProperties({"teachers", "states", "reviews"})
#OneToOne(cascade=CascadeType.ALL)
#JoinColumn(name = "course_code", referencedColumnName="code")
private Course course;
Registration class
#Entity(name = "Registration")
#Table(name = "registration")
public class Registration {
#EmbeddedId
private RegistrationId id;
When you're using a relational DB, you are setting entities with relationships between these entities.
The error that you're getting means that:
You're trying to delete a record that its primary key is functioning as a foreign key in another table, thus you can't delete it.
In order to delete that record, first, delete the record with the foreign key, and then delete the original that you wanted to delete.
I made it work by using hibernate #OnDelete annotation. Some how the JPA.persistence CascadeTypes were not working. They had no effect for whichever I chose.
Just like below. Now I can remove the parent Student or the parent Course and all children(Registrations) are deleted with them.
#Embeddable
public class RegistrationId implements Serializable {
#JsonIgnoreProperties("notifications")
#OnDelete(action = OnDeleteAction.CASCADE)
#OneToOne
#JoinColumn(name = "student_pcn", referencedColumnName="pcn")
private Student student;
#JsonIgnoreProperties({"teachers", "states", "reviews"})
#OnDelete(action = OnDeleteAction.CASCADE)
#OneToOne
#JoinColumn(name = "course_code", referencedColumnName="code")
private Course course;
Foreign keys guarantee that an entry will exist in another table. This is a way of ensuring data integrity. SQL will never allow you to delete this entry while it still deletes in the other table. Either (1) this is letting you know you would have made a grave mistake by deleting this thing which is required or (2) you would like to put in a cascading delete so that not only is this entry deleted but so is what is supposed to be referencing it in the other table. Information on cascading deletes can be found here and written fairly easily (https://www.techonthenet.com/sql_server/foreign_keys/foreign_delete.php). If neither of these two descriptions fits you, evaluate why your foreign key relationship exists in the first place because it probably should not.
Try this method too. I got the answer with this method,This is just a test to remove.
Pay attention to the cascade!
MyUser Entity
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstname;
private String lastname;
private String mobile;
#Column(unique = true)
private String email;
private Long date;
private LocalTime localiime;
private LocalTime localiimeend;
#ManyToOne(fetch = FetchType.LAZY,cascade = CascadeType.MERGE)
#JoinColumn(foreignKey = #ForeignKey(name = "role_fk"))
private Role role;
Role Entity
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String description;
#OneToMany(mappedBy = "role", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<MyUser> users;
#ManyToOne (fetch = FetchType.LAZY,cascade = CascadeType.MERGE)
#JoinColumn(foreignKey = #ForeignKey(name = "rolecat_fk"))
private rolecat rolecat;
rolecat Entity
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#OneToMany(mappedBy = "rolecat", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
private List<Role> roles;

JPA auto-generated key not reflected in foreign key of child table

Parent Table:
#Table(name="parent_table_t")
public class ParentTable implements Serializable {
#Id
#Column(name="contact_id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer contactId;
---------
---------
#OneToOne (cascade = CascadeType.ALL, mappedBy = "parentTable")
private ChildTable childTable;
}
Child Table:
#Table(name="child_table_t")
public class ChildTable implements Serializable {
#Id
#Column(name="child_id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer childId;
#Column(name="contact_id")
private Integer contactId;
#JoinColumn(name="contact_id", referencedColumnName = "contact_id", insertable=false, updatable=false)
#OneToOne(cascade = CascadeType.ALL)
private ParentTable parentTable;
}
My requirement is when contact_id is generated in Parent_table_t, it should be copied into contact_id of child_table_t when saved.
When I am calling saveAndFlush / save on Parent Table Entity, it is:
Generating the auto-increment for Parent->contact_id.
But Child_table_t -> contact_id is always null.
Can someone please help in this.
I am using in-memorty hsqldb with spring-boot and JPA.
You marked the relationship #JoinColumn with insertable=false, updatable=false, likely because you have an integer mapping for the column as well. Unfortunately, these settings prevent JPA from setting it with values from the relationship, which instead is forced to set the column with the value in the contactId attribute.
Put the insertable=false, updatable=false on the #Column instead.

Jpa OneToMany with condition

I have 2 tables:
The first is "Persons":
person_id,
person_name
The second is "PersonsGraphs":
person_id1,
person_id2,
relation_type
I'm looking for a way to build a "family tree".
My first option is: load personGraphs into a HashTable and then recursively build the tree.
The second option I have come up with: use #OneToMany jpa-relation. This can work, but sometimes I have some relation_types that I want/don't want to include. Are there any options that would allow me to set some condition on the #OneToMany relation while using #JoinTable?
Thanks!
Oak
Try to use Hibernate #Where annotation, for example:
#Entity
public class Person {
#Id
#GeneratedValue
private Integer id;
private String name;
#Enumerated(EnumType.STRING)
private Gender gender;
#ManyToOne
private Person parent;
#Where(clause = "gender = 'MALE'")
#OneToMany(mappedBy = "person")
private List<Person> sons;
#Where(clause = "gender = 'FEMALE'")
#OneToMany(mappedBy = "person")
private List<Person> daughters;
}
public enum Gender {
MALE, FEMALE
}
I would recommend creating a Relationship class to model the join table.
Person - OneToMany - relations - Relationship - ManyToOne source - ManyToOne target
In EclipseLink you can add an Expression criteria to any relationship mapping,
http://wiki.eclipse.org/EclipseLink/Examples/JPA/MappingSelectionCriteria

efficient JPQL: update entities in #onetomany

i have two entities Customer and Order (trivial setters and getters excluded)
#Entity
public class Customer {
#GeneratedValue
#Id
private int id;
#OneToMany
List<Order> orderList;
}
#Entity
public class Order {
#GeneratedValue
#Id
private int id;
#ManyToOne
Customer customer;
private boolean paid;
public Order(Customer customer) {
this.customer = customer;
customer.getOrderList().add(this)
}
}
Now i want to set 'paid = true' for all the orders of a given customer
Below query seem to do the trick, but I get a feeling it is innefficient and the fact that i stored the reverse relationship in Customer.orderList hints that there should be some other way to do this.
UPDATE Order o SET o.paid = true WHERE EXISTS
(SELECT c.orderList FROM Customer c WHERE o MEMBER OF c.orderList AND c = :customer)
I'm using container managed transactions, glassfish and javaDb. But I'd prefer if improvements could be done in JPA/JPQL domain and not specific to container or db.
private id; ?? missed field type
Add to #OneToMany annotation,cascade = CascadeType.All
Customer entity = entityManager.find(Customer.class, id)
for (Order order : entity.getOrderList())
{
order.setPaid(true);
}
if you are using cantainer managed transaction then true will be saved to DB