One of the new features in 4.1 will be the addition of an actual API for loading entities by natural id. Yes previous versions had the ability to do natural id loading leveraging criteria queries, but that approach was very limiting. The new API will allow caching at both the Session and SessionFactory level in addition to providing a consistent API. The new approach has been made available for identifier based loading as well, again for consistency.

New methods have been added to the Session contract as a starting point (see source or javadoc for additional discussion):

public IdentifierLoadAccess byId(String entityName);
public IdentifierLoadAccess byId(Class entityClass);

public NaturalIdLoadAccess byNaturalId(String entityName);
public NaturalIdLoadAccess byNaturalId(Class entityClass);

public SimpleNaturalIdLoadAccess bySimpleNaturalId(String entityName);
public SimpleNaturalIdLoadAccess bySimpleNaturalId(Class entityClass);

All of the load access delegates have methods for getting an entity reference (getReference) and loading an entity (load). The distinction is similar to the older get and load methods on Session; getReference on load access delegates equate to Session.load and load on load access delegates equate to Session.get

public interface IdentifierLoadAccess {
    public IdentifierLoadAccess with(LockOptions lockOptions);
    public Object getReference(Serializable id);
    public Object load(Serializable id);

public interface NaturalIdLoadAccess {
    public NaturalIdLoadAccess with(LockOptions lockOptions);
    public NaturalIdLoadAccess using(String attributeName, Object value);
    public Object getReference();
    public Object load();

public interface SimpleNaturalIdLoadAccess {
    public SimpleNaturalIdLoadAccess with(LockOptions lockOptions);
    public Object getReference(Object naturalIdValue);
    public Object load(Object naturalIdValue);

So let's say we have an entity defining a natural id:

public class User {
    private Long id;
    private String username;

we can load instances of that class by natural id as follows:

session.byNaturalId( User.class ).using( "username", "steve" ).load();

That actually makes sure we get back an initialized instance, just like Session.get does. If we just want a possibly uninitialized reference we would use this instead:

session.byNaturalId( User.class ).using( "username", "steve" ).getReference();

Since the natural id here is simple (just a single attribute) we can make this even easier:

session.bySimpleNaturalId( User.class ).load( "steve" );
25. Jan 2012, 09:19 CET | Link
Adrien OpenWide

If I remember correctly, Hibernate 4 need at least Java 1.5. Why is this new API not using generics ? I understant the byId(String entityName) can't know the real type, it could still return a IdentifierLoadAccess<Object>

26. Jan 2012, 14:02 CET | Link

I thought too that the hibernate 4.0 api would have evolved to use more generics but methods like get/load/merge haven't been parameterized.

27. Jan 2012, 13:19 CET | Link

The issue is that Hibernate has a feature that causes problems with parameterizing those sigs, @Proxy. Specifically if you specify @Proxy.proxyClass to name an interface Hibernate uses that interface to define proxies used for lazy loading, not the class. The proxies are only castable to the interface (hierarchy), not the class (hierarchy). There is a discussion on the dev mailing list if you care to join in.

21. Mar 2012, 13:48 CET | Link
Jeremy Stone

How do I arrange that the new byNaturalId loading be L2 cached? (With old criteria approach, setCacheable/setCacheRegion could be used.)

Also is the new approach intelligent enough to know not to perform an (expensive) dirty check/session flush unnecessarily?

29. Mar 2012, 14:59 CET | Link
Guenther Demetz

Hi Jeremy,

29. Mar 2012, 15:01 CET | Link
Guenther Demetz

Hi Jeremy,

How do I arrange that the new byNaturalId loading be L2 cached?

Use @NaturalIdCache annotation

Also is the new approach intelligent enough to know not to perform an (expensive) dirty check/session flush unnecessarily?

Currently it is not very intelligent in that sense, for this purpose I opened Hibernate JIRA issue Please take a look at it and, if you like this as enhancement, please vote for it.

24. Oct 2012, 10:09 CET | Link
Jeremy Stone

Thanks Guenther (although rather belatedly). The JIRA issue addresses my concerns exactly.

Post Comment