Entity object as HQL parameter - java

I have the following question, which is not covered in Hibernate documentation. Or I just couldn't find the answer there. Googling doesn't give me details also.
If we use an Entity object as a parameter and bind it to an HQL using Query.setParameter, what happens next?
Does hibernate uses only an entity ID of a mapped parameter object to build the SQL 'where' query?
Or Hibernate uses some extra logic (maybe in some cases) which is not limited to ID only? For example, hibernate add additional fields in SQL which are not primary keys.
Is it dangerous to use detached Entity object as a parameter?
Thank you in advance!

In terms of the SQL it will simply compare using the ids. The entity you bind does not have to be managed within that session as the comment on your question suggests.
Essentially what happens is that Hibernate will attempt to resolve the entity type of the entity instance it is given. It will then use that type to bind the JDBC parameter value, which will write just the identifier. So the assumption here is that the entity instance can resolved to its "entity type". That is usually easy in most situations. Where it gets difficult is in the case of Hibernate-specific "entity name" features.

Related

About the use of #ForceDiscriminator/#DiscriminatorOptions(force=true)

Why is #ForceDiscriminator or its equivalent #DiscriminatorOptions(force=true) necessary in some cases of inheritance and polymorphic associations? It seems to be the only way to get the job done. Are there any reasons not to use it?
As I'm running over this again and again, I think it might help to clarify:
First, it is true that Hibernate does not require discrimination when using JOINED_TABLE mapping. However, it does require it when using SINGLE_TABLE. Even more importantly, other JPA providers mostly do require it.
What Hibernate actually does when performing a polymorphic JOINED_TABLE query is to create a discriminator named clazz on the fly, using a case-switch that checks for the presence of fields unique for concrete subclasses after outer-joining all tables involved in the inheritance-tree. You can clearly see this when including the "hibernate.show_sql" property in your persistence.xml. In my view this is probably the perfect solution for JOINED_TABLE queries, so the Hibernate folks are right to brag about it.
The matter is somewhat different when performing updates and deletes; here hibernate first queries your root-table for any keys that match the statement's where clause, and creates a virtual pkTable from the result. Then it performs a "DELETE FROM / UPDATE table WHERE pk IN pkTable" for any concrete class withing your inheritance tree; the IN operator causes an O(log(N)) subquery per table entry scanned, but it is likely in-memory, so it's not too bad from a performance perspective.
To answer your specific question, Hibernate simply doesn't see a problem here, and from a certain perspective they are correct. It would be incredibly easy for them to simply honour the #DiscriminatorValue annotations by injecting the discriminator values during entityManager.persist(), even if they do not actually use them. However, not honoring the discriminator column in JOINED_TABLE has the advantage (for Hibernate) to create a mild case of vendor lockin, and it is even defensible by pointing to superior technology.
#ForceDiscriminator or #DiscriminatorOptions(force=true) sure help to mitigate the pain a little, but you have to use them before the first entities are created, or be forced to manually add the missing discriminator values using SQL statements. If you dare to move away from Hibernate it at least costs you some code change to remove these Hibernate specific annotations, creating resistance against the migration. And that is obviously all that Hibernate cares about in this case.
In my experience, vendor lockin is the paradise every market leader's wildest dreams are about, because it is the machiavellian magic wand that protects market share without effort; it is therefore done whenever customers do not fight back and force a price upon the vendor that is higher than the benefits reaped. Who said that an Open Source world would be any different?
p.s, just to avoid any confusion: I am in no way affiliated to any JPA implementor.
p.p.s: What I usually do is ignore the problem until migration time; you can then formulate an SQL UPDATE ... FROM statement using the same case-switch-with-outer-joins trick Hibernate uses to fill in the missing discriminator values. It's actually quite easy once you have understood the basic principle.
Guys let me try to explain about #DiscriminatorOptions(Force=true).
Well , it is used in single table inheritence, i have recently used this in one of the scenario.
i have two entities which was mapped to single table. when i was trying to fetch the record for one entity i was getting list of result containg records from both the entities and this was my problem. To solve this problem i have used #DiscriminatorOptions(Force=true) which will create the predicate using Discriminator column with the specified value mapped to the corresponding entity.
so the query will be look like this after i used #DiscriminatorOptions(Force=true)
select *
from TABLE
where YOUR PREDICATE AND DiscriminatorColumn = DiscriminatorValue
I think this is more of my opinion but I think some will agree with me. I prefer the fact that Hibernate enables you to not use a discriminator. In several cases the discriminator isn't necessary.
For example, I have a Person entity which contains stuff like a name, a date of birth, etc. This entity can be used by several other entities like Employee or Customer. When I don't reference Person from other entities, but reference Employee or Customer instead, the discriminator isn't used as Hibernate is instructed to fetch either one.
#yannisf ForceDiscriminator is not the only solution to solve this issue.
You can do instanceof tests for each child class. Though this will be like hardcoding your classes in your code but is a cleaner way to solve the problem if the discriminator column is not populated.
This also helps your code avoid mixing jpa and hibernate annotations.
As pointed out by yannisf, instanceOf is kind of an antipattern in the OO world.
Another solution could be changing your entity mapping. Suppose an entity A has a refernce to a superclass B and B has child classes of type C1 and C2, the instead of A pointing to B, you can have C1 and C2 have a foreign key pointing to A. It all comes down to changing the entity design so as not to mix annotations.
Thanks
Vaibhav

How to get parent entity?

I use JPA 2 with Hibernate. There are two entity classes, CardElement and IdentityDocumentKind. The last one is an inherited entity of the first one. SINGLE_TABLE inheritance strategy is used. When I try to select an instance of the parent class by query from CardElement where id = '123456' the following error occures:
Object with id: 123456 was not of the specified subclass:
org.cp.cardsystem.CardElement (Discriminator: SDocClass)
I don't have a subclass for "SDocClass" discriminator value. Actually at the moment of developing IdentityDocumentKind class querying of CardElement was used widely across the application. So I can't create a subclass of CardElement for each discriminator value and replace CardElement with it in all existent queries. It would be cost too much efforts for me. Is there a way to instantiate parent entity class when SINGLE_TABLE inheritance strategy is used?
I am not sure if I understand your problem correctly. You are using Single Table strategy to store the whole inheritance hierarchy. However, you have only mapped some of the discriminators, and this time, it is the unmapped discriminator causing the problem (because Hibernate dunno what that subclass means). Am I understanding your problem correctly?
Consider work against a special DB view instead of the real table. That view expose only records with discriminator you can handle.
Problem is solved. I've annotated root entity class of inheritance hierarchy (CardElement) in this way: #DiscriminatorValue(value = "not null"). Now I can select objects of this class without creating subclass for each discriminator value. not null and null seem to be Hibernate's special discriminator values which match in discriminator column anything except null and null respectively. I've not found any information about these values in Hibernate's official documentation. So it could be some kind of undocumented feature.

Is there a way for selecting extra fields - not to be saved - in hibernate?

I want to execute the following sql in hibernate:
SELECT emp.*, utilsPkg.getEmployeeDisplayName(emp.id) FROM employee emp;
So far so good...
The thing is - I need it to be fetched to an entity - so I can update the employee.
Of course that the pl\sql function is not updateable nor part of the actual table...
How can I generate such an entity in hibernate - with a field that is calculated and not updateable?
Many thanks!
Using the #Formula annotation, as explained in the Hibernate documentation:
Sometimes, you want the Database to do some computation for you rather
than in the JVM, you might also create some kind of virtual column.
You can use a SQL fragment (aka formula) instead of mapping a property
into a column. This kind of property is read only (its value is
calculated by your formula fragment).
Use the #Transient annotation on the getter method for that property.
I'm not sure if I fully understand your question, but you can always use Hibernate entity lifecycle callbacks or you can provide it directly in your query:
select new MyEntity(o.column1, o.column2, utilsPkg.getEmployeeDisplayName(o.id)) from MyEntity as o where o.id = 5
Of course you must implement appropriate constructor.

Hibernate, fetch, HQL and hashCode()

I have a HQL query something ala'
SELECT myclass
FROM
MyClass myclass JOIN FETCH
myclass.anotherset sub JOIN FETCH
sub.yetanotherset
...
So, class MyClass has a property "anotherset" , which is a set containing instance of another class, lets call it MyClassTwo. And, class MyClassTwo has a property yetanotherset which is a set of a third type of class (with no further associations on it).
In this scenario, I'm having trouble with the hashCode implementation. Basically, the hashCode implementation of MyClassTwo, uses the "yetanotherset" property, and on the exact line it accesses the yetanothertest property, it fails with a LazyInitializationException.
org.hibernate.LazyInitializationException: illegal access to loading collection
I'm guessing, this is because the data from "yetanotherset" hasn't been fetched yet, but how do I fix this? I don't particularly like the idea of dumbing down the hashCode to ignore the property.
Additional question, does HQL ignore fetch=FetchType.EAGER as defined in XML or annotations, it seems like it does. But I cant verify this anywhere.
Implementing hashCode() using a mutable field is a bad idea: it makes storing the entity in a HashSet and modifying the mutable property impossible.
Implementing it in terms of a collection of other entities is an even worse idea: it forces the loading of the collection to compute the hashCode.
Choose a unique, immutable property (or set of properties) in your entity, and implement hashCode based on that. On last resort, you have the option of using the ID, but if it's autogenerated, you must not put it in a Set before the ID is generated.
This is hibernate's most famous exception and it is exactly as you described it. The session has been disconnected, transaction closed, and you are attempting to access this collection. JOIN FETCH in your HQL should force EAGER loading to occur regardless of whether than annotation is present.
I suspect that your annotations are malformed, you have missing or out of date jars, or some other problem of that type.
Bump your Hibernate logging level up to generate the SQL hibernate.SQL=debug and investigate exactly what SQL is being executed up to where you see this exception. This should indicate to you whether your hibernate configuration is behaving the way you think its configured.
Post more of your code and the logs and someone might be able to help you spot the error.

EclipseLink refuses to map native query on PostgreSQL to entity

I have a JPA entity class (one of many) and I can run JPQL queries on it, returning that entity without any problem. However, when I attempt to run any named native query that selects all the fields on the underlying table, instead of mapping to the entity and returning a list of that entity type, I get a java.util.Vector of object arrays containing the result set. That is, the data is being returned, but not mapped to the entity. This is made worse by Java's fake generics, because the error manifests itself as a NumberFormatException in the EL parser.
My query calling code:
return em.createNamedQuery("ClinicDoctor.findUnchangedByClinicSystemId",
ClinicDoctor.class)
.setParameter(1, clinicSystemId)
.getResultList();
When I switch EclipseLink logging to FINE and run a JPQL query, the column names selected exactly match the column names I'm selecting in the native query.
Am I missing something? Is there some flaming hoop I should be jumping through to get the mapping to work?
Wouldn't you know it, right after asking this question I discovered that I just had to set the result-class attribute on the <named-native-query/> tag in my orm.xml and it worked.

Categories