persistence
persistence copied to clipboard
Support for loading by natural-id
I propose the spec adds the ability to load by an entity's natural-id, if it has one.
In terms of the actual load, this could be handled by a Query ofc. What is interesting in this API though is that it can make efficient use of both the EntityManage caches as well as the "second level" cache. In other words it can be much more efficient. Similar to loading by id.
It would center around a new @NaturalId
annotation which you would place on the attribute(s) making up the entity's natural-id[1]:
@Entity
class Product {
@Id Integer id;
@NaturalId String sku;
...
}
And then an API to load-by-natural-id. This is how I defined the API in Hibernate (pseudo). I know the exact API will not be everyone's cup-of-tea, but for now I am just proposing the concept.
EntityManager em = ...;
Session session = em.unwrap( Session.class );
Product product = em.unwrap( Session.class )
.byNaturalId( Product.class )
.find( "123-45678" );
I chose that paradigm to avoid overloads for every conceivable options. JPA API prefers the overloads, so a more "JPA-y" API might be:
EntityManager em = ...;
Product product = em.loadByNaturalId( Product.class, "123-45678" );
Along with overloads for any options we want to allow.
Personally I'd say to restrict this to just basic and embeddable types. When doing this in Hibernate I also added the ability to annotate multiple attributes which indicates a "decomposed" composition. In retrospect I now think that was a mistake.
In Hibernate, we also added @NaturalIdCache
to control whether we should cache at the "second level".
So I just went looking to see if EclipseLink has something like this, and it turns out they do, though the language they use to describe it is a bit different.
And whereas Hibernate has a special API for natural id lookups, EclipseLink just treats it as an optimization of a query against the natural id fields that's only available when you call getSingleResult()
.
That's nice in the sense that it doesn't require addition of a new API. But my knee-jerk reaction is to think that the dedicated API is a bit nicer to use and a lot more explicit. But I'm not sure. This is something we should all think a bit more about.
Anyway, since both Hibernate and EclipseLink support this conceptually, it seems clear it belongs in the spec. I guess not for 3.2 though, since we would need to invest some real work into hammering out the API.