Cascade=delete doesn't delete related entities - java

I do have 2 entities:
1. User
2. Limits
User has a set of limits, so one-to-many relation is present. I do have a cascade type set to delete, so when User is deleted, all corresponding limits should be deleted as well.
<bag name="limits" cascade="delete">
<key column="USER_ID"/>
<one-to-many class="com.mac.kom.modules.limits.models.LimitsModel" />
</bag>
When I try to delete the User I do get an error
Caused by: java.sql.SQLException: ORA-01407: cannot update ("DB"."LIMITS"."USER_ID") to NULL
Any clues?

You should cascade delete-orphan.
delete tries to break the link between the both entities by clearing the FK field.
delete-orphan won't authorize having some LimitsModel without User and thus will delete the related LimitsModel record.

try this
<bag name="limits">
<key column="USER_ID" on-delete="cascade"/>
<one-to-many class="com.mac.kom.modules.limits.models.LimitsModel" />
</bag>

Related

Hibernate-Foreign key object Null on Select Query

I have two tables ex:User and Role. with many-to-one relation between User and Role (one User can contain many Roles)
I used SQL query to insert the data in to the User table with the role_id(assume pk of Role table) as foreign key.
Now,when I tried to fetch the records of User with a particular role.
i am using following code to fetch the User object.
User user=(User)session.get('User.class',user_id);
Role role=user.getRole();
On executing the above lines,some times I'm getting the User Object,some times not.
The relation mapping between the objects is as below.
<many-to-one name="role" class="com.example.Role" fetch="select">
<column name="role_id" precision="14" scale="0" />
</many-to-one>
<set name="user" cascade="delete" table="User" >
<key>
<column name="role_id" not-null="true" />
</key>
<one-to-many class="com.example.User" />
</set>
Is there any way to prevent it occuring?
Is this possible that some times the select query will give me output and sometimes null.
There seem to be a fundamental mistake in your design. You stated that one User can contain Many Roles. This means foreign key (which points the PK of User) should be in Roles. But you seem to have put the foreign key in User.
Aside from DUKE answer who clearly pointed that your mapping says that a Role has many users as opposed to your requirement, there are still some issues with your code:
First you need to add inverse="true" to your one-to-many side. Since you have a bi-directional association, only one side can own the relationship:
<set name="user" cascade="delete" table="User" inverse="true">
<key>
<column name="role_id" not-null="true" />
</key>
<one-to-many class="com.example.User" />
</set>
And then it's much more efficient to fetch the Role in the same query with the User:
User user = (User)
session.createQuery(
"select u from User left join fetch u.role where u.id = :user_id')
.setParameter("user_id", user_id)
.uniqueResult();

Hibernate performs delete cascade in wrong order

My Db is throwing a Constraing violation (FK) because Hibernate performs a cascade delete in the wrong order.
Details:
I delete a Member, that has a Wallet with Wallet transactions (value-type), and the wallet transaction has an association to a product just like the Member contains collection of products (see the Hibernate mapping below).
I delete a Member instance, and want Hibernate to remove both the products and Wallet transactions. It seems that it first removes the product instances (through cascading), such that a FK violation is thrown by the DB, as it's still referenced by a Wallet transaction, that wasn't removed yet (through cascade)
I played around with the cascade setting, like all-delete-orphan (on the products), etc..., but no luck
I also emptied the wallet transactions and flushed the hibernate session in the same removal transaction, but also the same error.
Please some understanding and help to get the order of cascade deletion correct?
The hibernate mapping (I left out the none-important parts like PK and properties):
<class name="Member" table="mem" >
<component name="wallet" class="Wallet">
<set name="transactions" table="wallet_tx" cascade="all">
<cache usage="read-write" />
<key column="idTaxer" not-null="true" />
<composite-element class="WalletTransaction">
<property name="amount" type="big_decimal" column="amount" />
<many-to-one name="product" column="idPrdInst" class="Product" cascade="none" />
</composite-element>
</set>
</component>
<set name="products" cascade="delete" inverse="true">
<key column="idTaxer" not-null="true" />
<one-to-many class="Product" />
</set>
</class>
<class name="Product" table="prd" >
...
<many-to-one name="member" column="idMember" class="Member" cascade="none" />
</class>
The DB error:
ERROR: update or delete on table "prd" violates foreign key constraint "fk_1umej7" on table "wallet_tx"
DETAIL: Key (id)=(75bef42fc4544) is still referenced from table "wallet_tx".
If you empty the wallet transaction and expect it to be deleted you must set delete-orphan on the transactions relationship.
If product is still deleted 1st, you can flush after removing the wallet tx from the transaction set, it will work but it's surely not the state-of-art way.
Otherwise you could try to map the product - transaction oneToMany relationship and set a delete cascade on it (with inverse), the product deletion will so first trigger the transaction deletion.
Instead of:
<set name="transactions" table="wallet_tx" cascade="all">
you should have:
<set name="transactions" table="wallet_tx" cascade="all-delete-orphan">
And simply clear the transactions Set prior to deleting the Member parent entity.

Map hibernate many-to-one with the foreign key in subclass joined table

I'm mapping some entities using Hibernate 3 for my project and simply explained I've got kind of this:
Student entity (tstudent table)
UniversityStudent entity (tuniversitystudent table)
University entity (tuniversity table)
UniversityStudent extends from Student and has its own attributes, like the university itself, which is a foreign key into the tuniversitystudent table. It is also mapped like a subclass into the Student class, using a discriminator field:
<class name="mycompany.Student" table="tstudent" discriminator-value="BASIC">
<id name="id" column="id" type="integer">
<generator class="native" />
</id>
<discriminator column="type" />
<property name="name" column="name" />
<property name="surname" column="surname" />
<property name="phoneNumber" column="phone_number" />
<subclass discriminator-value="UNIVERSITY"
name="mycompany.UniversityStudent">
<join table="tuniversitystudent">
<key column="id_student" />
<many-to-one name="university" class="mycompany.University">
<column name="id_university" />
</many-to-one>
</join>
</subclass>
</class>
Well, now I want to have a Set collection with the UniversityStudent entities for each University. So I map it like that:
<class name="mycompany.University" table="tuniversity">
<id name="id" column="id" type="integer">
<generator class="native" />
</id>
<property name="name" column="name" />
<set name="universityStudents" table="tuniversitystudent">
<key>
<column name="id_university" />
</key>
<one-to-many class="mycompany.UniversityStudent" />
</set>
</class>
My problem comes when I want to load a University object, Hibernate complains that id_university doesn't exist in tstudent table. I checked the generated SQL query and it really tries to load it from tstudent.
Unknown column 'student0_.id_university' in 'field list'
It seems that it's recognizing that it is a subclass of the basic Student and tries to join the collection using a field in the parent table, but however the field is actually in the child table, because only university students can have a University assigned.
I tried another workaround which seems to work but it's not valid for me, that's mapping the UniversityStudent as a joined-subclass instead of a subclass with a join inside:
<joined-subclass name="mycompany.UniversityStudent" table="tuniversitystudent">
<key column="id_student" />
<many-to-one name="university" class="mycompany.University">
<column name="id_university" />
</many-to-one>
</joined-subclass>
However, I'm interested in keeping it as a subclass with a discriminator value. Any idea?
I checked out some resources and finally got into this bug: https://hibernate.atlassian.net/browse/HHH-1015, which looks absolutely compatible with your case. Checkout this old question as well, again very similar to your case.
I firstly read the definition of table per sublass given by Hibernate (I know, it is for version 3.3 but I couldn't find the same source for Hibernate 4): joined-subclass seems (to me) to be a custom implementation of subclass using a discriminator provided by Hibernate and that is a good reason to stay away from its usage. However, from what I know, the mappings table per sublass and table per subclass using a discriminator should be equivalent, that's why I believe the bug I pointed you out is really still open.
If you have time and will, you can try to use another JPA provider and check if you still run in the same issue. JPA 2.0 specifications is a thing, provider implementation is another! I recently run into another bug (related to #IdClass) which forced me to try EclipseLink and the configuration which was not working with Hibernate was right with Eclipse Link
Seems you can use Custom SQL (or HQL) for loading. Haven't tried it myself, but looks like, hmm, at least as a last resort, it provides a decent solution.
Define the query in your HBM:
<sql-query name="universityStudents">
<load-collection alias="unistu" role="University.universityStudents"/>
SELECT unistu.*, student.*
FROM tuniversitystudent unistu
JOIN tstudent student
ON unistu.id_student = student.id
WHERE unistu.id_university = :id
</sql-query>
And then use it inside University:
<set name="universityStudents" inverse="true">
<key/>
<one-to-many class="mycompany.UniversityStudent"/>
<loader query-ref="universityStudents"/>
</set>

Hibernate Mapping of Join Table with Meta Data

I'm trying to figure out how to map the relationship between two tables through a join table that has some meta data in it. In short, the three tables represent the page of a form, and each page can contain any number of elements (questions.) For some reason, the original developer decided that elements could be used on multiple forms. This means that the weight column, used to order the elements on the page, is in the join table.
How the heck do I map this in XML? (Annotations aren't an option.)
For the join table, I guess it's like this:
<class name="com.foo.bar.model.db.ApplicationPageElements"
table="APPLICATION_PAGE_ELEMENTS">
<composite-id name="id" class="com.foo.bar.model.db.ApplicationPageElementsKey">
<key-property name="pageId" column="page_id"/>
<key-property name="elementId" column="element_id"/>
</composite-id>
<property name="weight" type="java.lang.Long">
<column name="WEIGHT" precision="0" />
</property>
</class>
My instincts have me wanting to do something like this from the ApplicationPage side of things:
<set name="applicationElements" table="applicationPageElement">
<key column="page_id"/>
<many-to-many column="element_id" unique="true"
class="com.foo.bar.model.db.ApplicationElements" />
</set>
And that's where I get all slack-jawed, stare at the screen, and sob.
We're using .hbm.xml files to map our database. We also made the decision to not change our database.
Any ideas on how to map this in XML?
Instead of thinking of the relationship between application_page and application_element as many to many, think of it as a one to many relationship from application_page to ApplicationPageElements and a one to many relationship from application_element to ApplicationPageElements.
In your application_page xml mapping add this:
<set name="applicationElements" inverse="true">
<key column="page_id"/>
<one-to-many class="ApplicationPageElements"/>
</set>
page_id forms a part of the primary key of the join table. So, mark the collection as inverse.
Your mapping for the join table is correct. But, with the above change current mapping of your join table you can navigate from application_page to ApplicationPageElements. To navigate from application_page to application_element (via ApplicationPageElements) add a many to one relationship in join table mapping.
<class name="com.foo.bar.model.db.ApplicationPageElements"
table="APPLICATION_PAGE_ELEMENTS">
<composite-id name="id" class="com.foo.bar.model.db.ApplicationPageElementsKey">
<key-property name="pageId" column="page_id"/>
<key-property name="elementId" column="element_id"/>
</composite-id>
<property name="weight" type="java.lang.Long">
<column name="WEIGHT" precision="0" />
</property>
<many-to-one name="elements" class="ApplicationElements"
column="element_id" not-null="true" insert="false" update="false"/>
<many-to-one name="page" class="ApplicationPage"
column="page_id" not-null="true" insert="false" update="false"/>
</class>
Note that in the above many-to-one mapping, insert and update attributes are set to false. This is necessary because the columns are mapped twice, once in the composite key (which is responsible for insertion of the values) and again for the many-to-one associations.
The above use case is mentioned in detail in the book: Java Persistence with Hibernate.

Hibernate mapping collection by column

lets take this example
<class name="Product">
<id name="serialNumber" column="productSerialNumber"/>
<property name="category" column="category" />
<set name="categories">
<key column="productSerialNumber_FK" not-null="true"/>
<one-to-many class="Part"/>
</set>
The collection mapping always maps with the id from the class, which holds the foreign key. Is it possible to let hibernate map the collection through an other property/column? So that in this example category is mapped against the class Part?
Check out the property-ref attribute.
You can use the property-ref attribute in one-to-one many-to-one mappings. (That is, the other 'end' of the relationship).
However, in your example, you display a 'set', where you can specify the 'key column'. Though I see that you've specified a foreign-key name there, you can also specify the columnname.

Categories