Reputation: 24885
In my project, I have a JPA hierarchy Location -> Site
.
@Entity
@Table(name = "LOCATION")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="LOC_TYPE",discriminatorType=DiscriminatorType.STRING)
public class Location {
...
}
@Entity
@DiscriminatorValue("SI")
public class Site extends Location {
...
}
Now, every Employee
has a list of Location
assigned (even if, as far as I can tell, all such locations are actually Site
). In some part, I need the list of Site
s an Employee
has assigned to (note, the relationship I have defined was to Location
s).
With Hibernate 3.2, I can just write the query for Location
and filter by the discriminant; the classes returned are instances of the more specific subclass, v.g.:
Query query = em.createQuery("SELECT loc FROM Location loc WHERE loc.type=\"SI\"");
List<Location> locations = (List<Location>) query.getResultList();
for (Location location : locations) {
Site mySite = (Site) location;
...
}
However, I fail to find any documentation that tells if this behaviour is guaranteed by the JPA specification or is just an implementation decision from Hibernate. In the last case, I should not use that approach since it may change if I switch providers).
Can you tell me if my approach is supported by the standard?
BTW, I am using JPA 1 on Hibernate 3.2
UPDATE:
In orden to clarify what I want, this is the "safety alarm" that I have implemented. Keep in mind that the disc
property is the discriminator column, so I am sure that the objects returned where persisted as Site
instances.
Query query = em.createQuery("SELECT lo FROM Employee em JOIN em.location lo WHERE lo.disc = 'SI'");
List<Location> locations = (List<Location>) query.getResultList();
List<Site> site = new ArrayList<Site>();
for (Location location : locations) {
if (location instanceof Site) {
sites.add((Site) location);
} else {
log.warn("Found a Location that is not instance of Site");
}
}
Does the JPA specification specify that my log.warn
statement will never be called? AFAIK, maybe an implementation can return a bunch of Location
that are not instances of Site
. Of course, in that case only the Location
properties would be available; the behavior being somewhat like slicing in C++.
Upvotes: 4
Views: 837
Reputation: 19002
In JPA beginning with version 2.0 you have the TYPE(e)
function. Example from the spec:
SELECT e FROM Employee e WHERE TYPE(e) IN (Exempt, Contractor)
Excerpt from the JPA 2.0 spec (4.6.17.4 Entity Type Expressions):
An entity type expression can be used to restrict query polymorphism. The TYPE operator returns the exact type of the argument.
Note JPA. On the other side, your example casts doubt on the basic JPA mechanisms and I want to underline that again: when you fetch an row (using JPA queries) from DB with its discriminator value specific to the Site
entity, you can be sure that the Java object will be an instance of that class (i.e of the Site
class). Now I believe that the specification does not force the providers that its class is Site
(i.e fetchedEntity.getClass()==Site.class
), but you can be 100% sure that fetchedEntity instanceof Site
returns true.
Note Hibernate. From my experience with Hibernate I can only add that fetchedEntity.getClass() == Site.class
returns true in Hibernate (of course beside the fact that fetchedEntity instanceof Site
).
Upvotes: 5