Hibernate make joins on save cascade - java

Let´s say I have an entity A that has a relationship oneToMany with B with cascade ALL type and by default lazy.
My question now is, what happend, if now I modify A, but B keep in session exactly the same, and I save A. Hibernate will do the join with B and he will update on database, or he will keep B as hibernate proxy?.
We´re facing some problems on our application, since MySQL is complaining for the maximum number of joins when we save the top level entity.
ERROR 1116 (HY000): Too many tables; MySQL can only use 61 tablesin a join
Regards.

I had a similar problem, but with eager fetched relationships. Once we changed them to lazy, the problem was gone.
Hibernate shouldn't make joins with other lazy-related tables when updating only table A in your example, but best is to print out the generated SQL and see if and how it changes when you change your fetch settings.

Related

Figuring out from Hibernate how entity relations are configured

Is it possible to retrieve from Hibernate (5) how the relationships between entities are configured?
My use case is the following: I have a web service that provides (read) access to data in a relational database. The data consists of multiple entities and some of them are related through foreign keys (the usual one-to-one, one-to-many, many-to-one, many-to-many). When requesting data, client can specify a filter and, in the filter, they can freely traverse entity relationships. Something needs to translate the filter into something Hibernate understands though. Currently, we are generating Criteria.
As an example, suppose we have 2 entities, A and B, where the property A.bees refers to a collection of B. This is mapped in Hibernate by having a foreign-key column in B referring to the primary key of A. A user can then request all As having at least one B with B.name starting with 'Bla'. The request specifies that we're looking for results of type A, and its filter part would look something like:
<like>
<property>bees.name</property>
<literal>Bla*</literal>
</like>
The problem is: my service does not control the Hibernate mapping and so does not know how the relations are configured or even which entities exist. It just loads the mapping, translates and applies the filter and spits out whatever data gets returned by Hibernate. I cannot change the request content as that is per a specification (actually OGC Filter).
So far, I am able to find the right entities and follow the property path, encountering property AssociationTypes and EntityMetadata along the way and translate all filter elements into individual Criterions. What I am not able to do is to find how the entities are related: in the example, the fact that "B has a foreign-key referring to the primary key of A". Could anyone tell me how to get that information?
I'm not sure I quite understood your database access permissions, but if you can connect to the database, you can use JDBC's DatabaseMetaData class and it's exported keys method:
https://docs.oracle.com/javase/7/docs/api/java/sql/DatabaseMetaData.html#getExportedKeys(java.lang.String,%20java.lang.String,%20java.lang.String)
Turns out I misunderstood how this is supposed to be done in Hibernate. I was using the Criteria API to generate the query that I would write myself:
session.createCriteria("A")
.add(Property.forName("id").in(
DetachedCriteria.forEntityName("B")
.add(Restrictions.like("name", "Bla%"))
.setProjection(Projections.property("fk_a"))))
The resulting query is (pretty much)
SELECT a.*
FROM A a
WHERE a.id IN (SELECT b.fk_a
FROM B b
WHERE b.name LIKE 'Bla%')
The problem was that I did not know the names id and fk_a.
What I should have done instead (and am now doing) is simply let Hibernate do the join.
session.createCriteria("A")
.createAlias("B", "b")
.add(Restrictions.like("b.name", "Bla%"))
.setResultTransformer(DistinctRootEntityResultTransformer.INSTANCE)
The resulting query from this is (pretty much)
SELECT a.*, b.*
FROM A a INNER JOIN B b ON a.id = b.fk_a
WHERE b.name LIKE 'Bla%')
Now I don't need to know the names of the primary and foreign key properties.
The obvious downside of this approach is that more data is transferred from the server to the client as the cartesian product of A's and related B's is returned. We get the expected answer by indicating that we are only interested in distinct root entities. The transformer runs on the client side though, so it really does not help cut down on traffic.

Hibernate NonUniqueObjectException

I'm getting NonUniqueObjectException in hibernate.
There is one Item class, I saved list of Item objects using session.save of hibernate.
Now in the same transaction, I'm trying to update same Items using raw sql query which has join with another table. This gives me NonUniqueObjectException. The two tables I'm joining are unrelated as entities for hibernate, that is, there is no foreign key relation.
So I have 2 questions:
First, is there any way of using hql for writing inner join queries in hibernate.
Second, how to avoid NonUniqueObjectException.
One of the things that is working is that I clear the session before making any raw sql query. Any better approach is welcomed.

How change hibernate association mapping from 'one to many' into 'many to many'?

The relation between the entities must be changed and I'd like to know is it normal to change the association mapping type and whether the data that already exist in db will be transfered normally? I tried to find information about it but didn't found. Or if the mapping will be changed the data that already exists must be transfered manually via sql queries? Thanks
If the association already uses a join table, and the mapping of the many-to-many keeps using the same join table with the same column names, you won't have to do anything except removing the unicity constraint you could have on one of the ci=olumns of the join table.
Otherwise, yes, obviously, you'll have to migrate your schema, using SQL, or any other tool (FlywayDB, Liquibase, etc.).
I could do it simply:
Let A and B be the original tables.
A->B (N-1) was moved to A<-AB->B (N-N).
I had to
- "remove" the foreignkey column from table A,
in favor of records to be inserted into AB
(made of the two foreign keys leading to A and B)
That's all.
Step one: Replace your Many-to-One annotation by your Many-to-Many annotations.
and lauch hibernate in append mode to generate the N-N table
Step two: Insert record in this N-N table given what is found in the remaining foreign-key column of you 1-N relationship.
Step three: Delete this foreign-key column.

Update all table data at a time in JPA

Is it possible to update all table data in one query?
I have a Database table Person and corresponding Entiry PersonEntity, I can get all Person data vi a JPA in a list such as List personAll.
I have several CRUD operation on personAll instance, I want to reflect all these changes to the Database in one hand using Hibernate JPA
In other words I want content of Person Table is replaced with new content of personAll instance?
Actually long solution way of this question is execute several insert, delete and update operations. But there should be a easy way of doing it?
I can do similar thing when there are two tables Shool Student table if there is OneToMany relation between eash other? Hibernate JPA value removing OneToMany relation
Thanks
It depends on how many rows there are in your table.
If you load all the rows into a Hibernate session and modify the returned instances as required, any changes will be automatically persisted to the database by Hibernate when the session is flushed.
The reason it depends on the size is that if you load the contents of a huge table into a Hibernate session you risk out of memory errors and even if you don't run out of memory the flush will be very slow since every entity in the session much be checked for modifications.

Hibernate bulk update leads to in-query which takes for ever to complete

Article entity is a sub-class of the Product entity. The inheritance strategy for them is joined. Article#flag is a boolean attribute which I want to set false for all articles. Hence, I do
Query query = entityManager.createQuery("update Article set flag=:flagValue");
query.setParameter("flagValue", false);
query.executeUpdate();
I expected this to lead to a single SQL statement against the database which should complete fairly quickly. Instead Hibernate populates a temporary table (which does not physically exist in the database) and runs an in-query ie. the update later:
insert into HT_article select article0_.id as id from schema.article article0_ inner join schema.product article0_1_ on article0_.id=article0_1_.id
update schema.article set flag=0 where (id) IN (select id from HT_article)
The actual update statement takes "forever" to complete and locks the affected articles thereby causing lock exceptions in other transactions. By forever I mean more than an hour for 130000 articles.
What's the explanation for this behavior and how could I solve it? Other than running a native query I mean...
Update 2011-05-12: it's terribly slow because the in-query is slow, I filed a bug for that -> http://opensource.atlassian.com/projects/hibernate/browse/HHH-5905
I am using InheritanceType.JOINED of hibernate and faced a similar issue where hibernate was inserting into the temp table and was taking ages to delete the entities. I was using createQuery and executeUpdate to delete the records which caused the issue.
Started using session.delete(entity) which solved the issue for me.
Because you're using InheritanceType.JOINED, Hibernate has no choice but to unify the subclass and its base class.
If you switched to InheritanceType.TABLE_PER_CLASS (http://openjpa.apache.org/builds/1.0.2/apache-openjpa-1.0.2/docs/manual/jpa_overview_mapping_inher.html) you'd avoid this and get your performance back. But I'm sure you're using JOINED for a reason :-(

Categories