Delete all slaves with an object in HQL - java

I use following HQL query to delete a specific object in my database.
delete from com.ranking.Footballclub where id = 1
The problem I encounter when I do this, it breaks a foreign key.
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: The DELETE
statement conflicted with the REFERENCE constraint
"FK_VKLC3OLNFZIT2FCYMMKDO2ERZ4". The conflict occurred in database
"sports", table "dbo.FOOTBALL_PLAYER", column 'CLUB_ID'
A sport teams has a slave of players. I could first delete all players before I delete the Footballclub. But a Footballclub has more than just players. It has for example a list of employees, transfers,... Their foreign keys will break as well.
For this case I'm looking for something in HQL to delete all slave fields in 1 statement.

you can set the ON DELETE CASCADE in the data base explicitly, or mark the required Child entity with the annotation #org.hibernate.annotations.OnDelete.
It will automatically adds the on delete to schema during the schema generation. like -
#OneToMany(fetch = FetchType.EAGER, mappedBy = "YOUR_PARENT",
cascade = CascadeType.REMOVE)
#org.hibernate.annotations.OnDelete(
action = #org.hibernate.annotations.OnDeleteAction.CASCADE)
private List<YOUR_CHILD> CHILDS;

You can only use #OneToMany(cascade=CascadeType.REMOVE) annotation at your Entity and delete it through entity manager. There is no option to do it with hql. Or use constraint in your DDL (foreign key delete cascade);

Related

Cannot delete a parent row: a foreign key constraint fail

I have 2 entities (User , Teacher) the User is the father ...
When I want to remove user by native query it give me this error ( Cannot delete or update a parent row: a foreign key constraint fail )
Though I have written:
#OneToOne(mappedBy = "user_id",fetch = FetchType.EAGER,
cascade = CascadeType.ALL , orphanRemoval = true )
at the Teacher reference in the user entity
but when I try to use JPA derived method deleteByEmail() .. it worked!
What is the reason?
Cascading doesn't work with queries.
It works when you change the state of the entities using the methods in the EntityManager or Hibernate ORM Session.
You can see a list of examples in the Hibernate ORM documentation:
5.15. Cascading entity state transitions.

Used only #mappedBy , not #JoinColumn - join column created in OneToMany relationship, what is then the use of JoinColumn?

I am new to Hibernate. I have a OneToMany relationship with bidirectional mapping between Account and Transaction. I am not using #JoinColumn in either class and using #mappedBy in the non owning Account class. And everything is working fine. Using H2 in memory database, new join column is created in Transaction table. Then what is the use of #JoinColumn in OneToMany relationships? Is it for unidirectional mapping only? Below is the code. I also read for reference JPA JoinColumn vs mappedBy
public class Account {
#OneToMany( mappedBy="account", cascade=CascadeType.ALL)
List<Transaction> list= new ArrayList<Transaction>();
}
public class Transaction {
#ManyToOne
Account account;
}
Application class :
Account a = new Account("savings");
Transaction t1 = new Transaction("shoe purchase", 45);
t1.setAccount(a);
a.getList().add(t1);
accountRepository.save(a);
output:
Transaction table has an entry with foreign key which is account number in that one row in Account table. ACCOUNT_ID column in created in Transaction table.
There are no extra tables created.
Jpa works on the idea of configuration by convention. So, it will perform configuration on your behalf whenever it can. Think of the #Column annotation, you don't have to apply it on every entity attribute, you would need it only when you have to change something about the attributes.
It's the same with #JoinColumn, when you added #ManyToOne, Jpa already knows that you will need the join column and thus was added for you and the default naming convention for the foreign key was applied (attributename_primarykeyoftheothertype).
Use of
mappedBy
is instruct framework to enable bi-directional relationship. Because of #ManyToOne on Transaction class you Your Transaction Table will have foreign key referring to Account table primary key. By default, Hibernate generates the name of the foreign key column based on the name of the relationship mapping attribute and the name of the primary key attribute. In this example, Hibernate would use a column with the name account_id to store the foreign key to the Account entity.
#JoinColum
can be used If you would like override default foreign key name like #JoinColum(name="acc_id")
MappedBy intructs Hibernate that the key used for the association is on the other side of the association.Like in this case ACCOUNT_ID is being created on Account table.
That means that although you associate two tables together, only one table is having foreign key constraint to the other one.
MappedBylets you to still associate from the table not having foreign key constraint to the other table.

Hibernate delete from onetomany

I have two tables with OneToMany relation
class ServiceProvider {
...
#OneToMany(fetch=FetchType.EAGER,mappedBy="serviceProvider",
cascade={CascadeType.ALL,CascadeType.REMOVE},orphanRemoval = true)
#OnDelete(action=OnDeleteAction.CASCADE) private
List serviceCenters; ...
}
class ServiceCenterDetails {
... //bi-directional many-to-one association to
ServiceProviderDomainMap #ManyToOne
#JoinColumn(name="SERVICE_PROVIDER_ID") private ServiceProvider
serviceProvider;
...
}
I am trying to delete provide row. But i am getting below error:
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails (fixoline.service_center_details, CONSTRAINT FK_qvahoxeovx9vmwl6mcu2c0lyw FOREIGN KEY (SERVICE_PROVIDER_ID) REFERENCES service_provider (ID))
below is the way i am trying
String hql = "DELETE FROM ServiceProvider WHERE id = :providerId";
Query query = sessionFactory.getCurrentSession().createQuery(hql);
query.setParameter("providerId",providerId);
int result = query.executeUpdate();
could someone pls help resolving it?
There are two tings,
Why you are using #OnDelete when you using CascadeType.ALL in #oneToMany? CascadeType.ALL will delete child entities when parent is deleted.
#OnDelete mainly used in child entities with #ManyToOne not otherwise.
Try with any option and check.
The error message is quite clear: There are foreign key references to the ServiceProviders you are trying to delete. Delete ServiceCenterDetails first:
delete from ServiceCenterDetails where serviceProvider.id = :providerId
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot delete or update a parent row: a foreign key constraint fails
this exception tells that you should delete your ServiceCenterDetails associated with ServiceProviders first and then delete the ServiceProviders.

How to automatically remove child entities?

I'd like to remove entities from my table and have it auto-removed any entities that are childs of it.
Example:
class User {
#OneToMany(cascade = CascadeType.ALL, mappedBy = "user", orphanRemoval=true)
#OnDelete(action = OnDeleteAction.CASCADE)
List<Address> addresses;
}
When I remove a User that has no address, everything works fine. Also removing an address without removing the user works.
But: If I try to remove a user that has still some addresses, I'm getting org.hsqldb.HsqlException:
integrity constraint violation: foreign key no action; FK_ADDRESS_USER_ID table: ADDRESS
What might be wrong here?
Or is this not supported and I have to explicitly remove all contained Address objects first before deleting a user?
I believe you have a problem with a foreign key constraint. Use a DB tool like Aqua Data Studio or similar (you can probably also do this in your IDE, in Eclipse - Data Source Explorer view), to show the create script for your ADDRESS table. It should contain something like this:
ALTER TABLE TESTSCHEMA.ADDRESS
ADD CONSTRAINT FK1ED033D4E91AAFD9
FOREIGN KEY(FK_ADDRESS_USER_ID)
REFERENCES TESTSCHEMA.USER(ID)
ON DELETE CASCADE
The point being the ON DELETE CASCADE part in your case. If this is missing or is different, that probably is what is causing the problem. If the table is auto-generated by Hibernate, this constraint should be valid, but keep in mind that there are differences between databases. It could be that the table was generated before the Hibernate's #OnDelete annotation was added, so now you are getting the "foreign key no action" integrity constraint violation.
Not related to the issue, but do note that orphanRemoval=true will try to remove the address from the database, when it is removed from the collection in the User entity.
Also, check this out for details on Hibernate’s support for database ON DELETE CASCADE constraint.

How to batch delete using bulkUpdate

I have a common User / Role setup, with a user_role join table. I'm trying to use Spring's HibernateTemplate to mass delete all locked users like this:
getHibernateTemplate().bulkUpdate("delete from User where locked=?", true);
If the user being deleted does not have any roles (no record in the user_role table), then everything goes fine; however if the user does have a role record, I'm getting the following error:
integrity constraint violated - child
record found
Roles are defined in User.java like this:
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "user_role", joinColumns = { #JoinColumn(name = "user_id") }, inverseJoinColumns = #JoinColumn(name = "role_id"))
private Set<Role> roles = new HashSet<Role>();
So how can I batch delete users even if a user has child records? Thanks!
Bulk delete operations are not cascaded to related entities as per the JPA specification:
4.10 Bulk Update and Delete Operations
Bulk update and delete operations
apply to entities of a single entity
class (together with its subclasses,
if any). Only one entity abstract
schema type may be specified in the
FROM or UPDATE clause.
...
A delete operation only applies to
entities of the specified class and
its subclasses. It does not cascade
to related entities.
However, I'd expect the JPA provider to deal with join tables. Sadly, Hibernate doesn't and this is logged in HHH-1917. I'm afraid you'll have to fall back on native SQL to clean up the join table yourself or to use cascading foreign keys in the schema.
Application-level cascading (cascading through hibernate annotations or JPA annotations) only work if the actual entity is actually loaded from the db. When you use the hibernate template with HQL, you'll notice that the entities are not loaded, and the HQL is directly converted to SQL to be executed.
If you want to batch delete you have to use an HQL query to delete all relevant tables (ie roles) before deleting the parent table data.
I'm not entirely sure because it's hard for me to recreate this problem, but I think you might need to add a cascade to your #ManyToMany
#ManyToMany(cascade = CascadeType.ALL)
Since you want to bulk delete something that have a ManyToMany related items, you first have to delete the relation (in the join table), or do a loop and for each item, delete manually (insane and too much heavy).
So, since JPQL does not allow to do it, a possible way is to make a native SQL query for deleting the id you want in the related table, and then, do the bulk delete.

Categories