Application-Level Views in Hibernate

In scenarios where direct database access is unavailable, Hibernate provides a powerful feature to define views at the application level. This approach allows developers to create virtual entities that map to custom query definitions without requiring actual database view creation.

Core Annotations

Hibernate offers three key annotations for implementing application-level views:

  • @Immutable - Marks the entity as read-only, preventing any modification operations
  • @Subselect - Embeds a SQL subquery that defines the view's data source
  • @Synchronize - Specifies which tables the subquery references, enabling automatic cache invalidation

Implementation Example

import javax.persistence.Entity; import javax.persistence.Id;

@Entity @org.hibernate.annotations.Immutable @org.hibernate.annotations.Subselect( value = "SELECT e.id AS entityId, " + "CONCAT(e.employee_name, '-profile') AS displayName " + "FROM Employee e" ) @org.hibernate.annotations.Synchronize({"Employee"}) public class EmployeeProfileView {

@Id
protected long entityId;
protected String displayName;

public long getEntityId() {
    return entityId;
}

public void setEntityId(long entityId) {
    this.entityId = entityId;
}

public String getDisplayName() {
    return displayName;
}

public void setDisplayName(String displayName) {
    this.displayName = displayName;
}

@Override
public String toString() {
    return "EmployeeProfileView [entityId=" + entityId + ", displayName=" + displayName + "]";
}

}


</div>Testing the View
----------------

<div>```
package com.example.persistence;

import static org.junit.Assert.assertNotNull;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

@RunWith(Parameterized.class)
public class EmployeeProfileViewTest {

    private Session currentSession;
    
    public EmployeeProfileViewTest(SessionFactory factory) {
        this.currentSession = factory.openSession();
    }
    
    @Parameters
    public static Collection sessionFactories() {
        return Arrays.asList(new Object[]{TestEnvironment.getFactory()});
    }
    
    @Before
    public void initialize() {
        currentSession.beginTransaction();
    }

    @After
    public void cleanup() {
        currentSession.getTransaction().commit();
    }

    @Test
    public void verifyViewDataRetrieval() {
        List results = currentSession
            .createQuery("SELECT v FROM EmployeeProfileView v")
            .getResultList();
        
        for(Object item : results) {
            System.out.println(item);
        }
        assertNotNull(results);
    }
}
    <property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
    <property name="hibernate.show_sql">true</property>
    <property name="hibernate.format_sql">true</property>
    <property name="hibernate.auto_quote_keyword">true</property>
    
    <!-- 
        Schema generation strategy:
        create - Drop and recreate tables on each session factory build
        create-drop - Same as create, plus automatic table deletion on shutdown
        update - Maintain schema incrementally, preserve existing data
        validate - Verify schema compatibility without modifications
    -->
    <property name="hibernate.hbm2ddl.auto">update</property>
    
    <mapping class="com.example.persistence.entity.Employee"/>
    <mapping class="com.example.persistence.entity.Department"/>
    <mapping class="com.example.persistence.entity.EmployeeProfileView"/>
</session-factory>

Tags: hibernate jpa subselect immutable-entity view-mapping

Posted on Tue, 03 Nov 2026 16:49:19 +0000 by phbock