Hibernate.orgCommunity Documentation

Hibernate OGM Reference Guide

Logo

5.0.4.Final


Preface
1. Goals
2. What we have today
3. Experimental features
4. Use cases
1. How to get help and contribute on Hibernate OGM
1.1. How to get help
1.2. How to contribute
1.2.1. How to build Hibernate OGM
1.2.2. How to contribute code effectively
1.3. How to build support for a data store
1.3.1. DataStore providers
1.3.2. Dialects
1.3.3. Entities
1.3.4. Associations
1.3.5. Configuration
1.3.6. Types
1.3.7. Tests
2. Getting started with Hibernate OGM
3. Architecture
3.1. General architecture
3.2. How is data persisted
3.3. Id generation using sequences
3.4. How is data queried
4. Configure and start Hibernate OGM
4.1. Bootstrapping Hibernate OGM
4.1.1. Using JPA
4.1.2. Using Hibernate ORM native APIs
4.2. Environments
4.2.1. In a Java EE container
4.2.2. In a standalone JTA environment
4.2.3. Without JTA
4.3. Configuration options
4.4. Configuring Hibernate Search
4.5. How to package Hibernate OGM applications for WildFly 10
4.5.1. Packaging Hibernate OGM applications for WildFly 10
4.5.2. Configure your persistence.xml to use your choice of persistence provider
4.5.3. Enabling both the Hibernate Search and Hibernate OGM modules
4.5.4. Using the Hibernate OGM modules with Infinispan
5. Map your entities
5.1. Supported entity mapping
5.2. Supported Types
5.3. Supported association mapping
6. Hibernate OGM APIs
6.1. Bootstrap Hibernate OGM
6.2. JPA and native Hibernate ORM APIs
6.2.1. Accessing the OgmSession API
6.3. On flush and transactions
6.3.1. Acting upon errors during application of changes
6.4. SPIs
7. Query your entities
7.1. Using JP-QL
7.2. Using the native query language of your NoSQL
7.3. Using Hibernate Search
7.4. Using the Criteria API
8. NoSQL datastores
8.1. Using a specific NoSQL datastore
9. Infinispan
9.1. Configure Infinispan
9.1.1. Adding Infinispan dependencies
9.1.2. Infinispan specific configuration properties
9.1.3. Cache names used by Hibernate OGM
9.2. Manage data size
9.3. Clustering: store data on multiple Infinispan nodes
9.4. Storage principles
9.4.1. Properties and built-in types
9.4.2. Identifiers
9.4.3. Entities
9.4.4. Associations
9.5. Transactions
9.6. Storing a Lucene index in Infinispan
10. Ehcache
10.1. Configure Ehcache
10.1.1. Adding Ehcache dependencies
10.1.2. Ehcache specific configuration properties
10.1.3. Cache names used by Hibernate OGM
10.2. Storage principles
10.2.1. Properties and built-in types
10.2.2. Identifiers
10.2.3. Entities
10.2.4. Associations
10.3. Transactions
11. MongoDB
11.1. Configuring MongoDB
11.1.1. Adding MongoDB dependencies
11.1.2. MongoDB specific configuration properties
11.1.3. FongoDB Provider
11.1.4. Annotation based configuration
11.1.5. Programmatic configuration
11.2. Storage principles
11.2.1. Properties and built-in types
11.2.2. Entities
11.2.3. Associations
11.3. Transactions
11.4. Optimistic Locking
11.5. Queries
11.5.1. JP-QL queries
11.5.2. Native MongoDB queries
11.5.3. Hibernate Search
12. Neo4j
12.1. How to add Neo4j integration
12.2. Configuring Neo4j
12.3. Storage principles
12.3.1. Properties and built-in types
12.3.2. Entities
12.3.3. Associations
12.3.4. Auto-generated Values
12.3.5. Labels summary
12.4. Transactions
12.5. Queries
12.5.1. JP-QL queries
12.5.2. Cypher queries
13. CouchDB (Experimental)
13.1. Configuring CouchDB
13.1.1. Annotation based configuration
13.1.2. Programmatic configuration
13.2. Storage principles
13.2.1. Properties and built-in types
13.2.2. Entities
13.2.3. Associations
13.3. Transactions
13.4. Queries
14. Cassandra (Experimental)
14.1. Configuring Cassandra
14.1.1. Adding Cassandra dependencies
14.1.2. Cassandra specific configuration properties
14.2. Storage principles
14.2.1. Properties and built-in types
14.3. Transactions and Concurrency
14.4. Native queries
15. Redis (Experimental)
15.1. Configuring Redis
15.1.1. Annotation based configuration
15.2. Storage principles
15.2.1. JSON mapping
15.2.2. Hash mapping
15.2.3. Associations
15.3. Identifiers
15.3.1. Identifier generation strategies
15.4. Transactions
15.5. Queries
15.6. Redis Cluster

Hibernate OGM is a persistence engine providing Java Persistence (JPA) support for NoSQL datastores. It reuses Hibernate ORM’s object life cycle management and (de)hydration engine but persists entities into a NoSQL store (key/value, document, column-oriented, etc) instead of a relational database.

It allows using the Java Persistence Query Language (JP-QL) as an interface to querying stored data, in addition to using native queries of the specific NoSQL database.

The project is now fairly mature when it comes to the storage strategies, and the feature set is sufficient to be used in your projects. We do have however much bigger ambitions than a simple object mapper. Many things are on the roadmap (more NoSQL, query, denormalization engine, etc). If you feel a feature is missing, report it to us. If you want to contribute, even better!

Hibernate OGM is released under the LGPL open source license.

Note

The future of this project is being shaped by the requests from our users. Please give us feedback on

  • what you like
  • what you don’t like
  • what is confusing
  • what you are missing as a feature

Check Section 1.2, “How to contribute” on how to contact us.

Tip

We worked hard on this documentation but we know it is far from perfect. If you find something confusing or feel that an explanation is missing, please let us know. Getting in touch is easy: see contacting the developer community.

Hibernate OGM:

NoSQL can be very disconcerting as it is composed of many disparate solutions with different benefits and drawbacks. NoSQL databases can be loosely classified in four families:


Each have different benefits and drawbacks and one solution might fit a use case better than an other. However access patterns and APIs are different from one product to the other.

Hibernate OGM is not expected to be the Rosetta stone used to interact with all NoSQL solution in all use cases. But for people modeling their data as a domain model, it provides distinctive advantages over raw APIs and has the benefit of providing an API and semantic known to Java developers. Reusing the same programmatic model and trying different (No)SQL engines will hopefully help people to explore alternative datastores.

Hibernate OGM also aims at helping people scale traditional relational databases by providing a NoSQL front-end and keeping the same JPA APIs and domain model. It could for example help to migrate a selection of your model from an RDBMS to a particular NoSQL solution which better fits the typical use case.

Hibernate OGM is a young project. Join and help us shape it!

First of all, make sure to read this reference documentation. This is the most comprehensive formal source of information. Of course, it is not perfect: feel free to come and ask for help, comment or propose improvements in our Hibernate OGM forum.

You can also:

  • open bug reports in JIRA
  • propose improvements on the development mailing list
  • join us on IRC to discuss developments and improvements (#hibernate-dev on freenode.net; you need to be registered on freenode: the room does not accept "anonymous" users).

Welcome!

There are many ways to contribute:

  • report bugs in JIRA
  • give feedback in the forum, IRC or the development mailing list
  • improve the documentation
  • fix bugs or contribute new features
  • propose and code a datastore dialect for your favorite NoSQL engine

Hibernate OGM’s code is available on GitHub at https://github.com/hibernate/hibernate-ogm.

Hibernate OGM supports various data stores by abstracting them with DatastoreProvider and GridDialect. The supported features vary between data stores, and dialects do not have to implement all features. Hibernate OGM implements a TCK (Technology Compatibility Kit) to verify interoperability and features of the dialect. Hibernate OGM supports a variety of document- and key-value-stores and ships with some abstraction and utility classes for document- and key-value-stores (like KeyValueStoreProperties and DocumentStoreProperties).

A data store can have one or more dialects. Dialects describe the style how data is mapped to a particular data store. NoSQL data stores imply a certain nature, how to map data. Document-oriented data stores encourage an entity-as-document pattern where embedded data structures could be stored within the document itself. Key-value data stores allow different approaches, e.g. storing an entity as JSON document or event storing individual key-value pairs that map the entity within a hash table data structure. Hibernate OGM allows multiple dialects per data store and users may choose the most appropriate one.

The most basic support is provided by implementing the GridDialect interface. Implementing that interface is mandatory to support a specific data store.

A GridDialect usually supports:

A dialect may optionally implement one or more additional facet interfaces to provide a broader support for certain features:

Features of a QueryableGridDialect

Features of a BatchableGridDialect

Features of a IdentityColumnAwareGridDialect

Features of an OptimisticLockingAwareGridDialect

Features of a MultigetGridDialect

Hibernate OGM is not opinionated by which means data is stored/loaded for a particular data store, but the particular dialect is. Hibernate OGM strives for the most natural mapping style. The idea is to facilitate integration with other applications of that database by sticking to established patterns and idioms of that store.

If you are familiar with JPA, you are almost good to go. We will nevertheless walk you through the first few steps of persisting and retrieving an entity using Hibernate OGM.

Before we can start, make sure you have the following tools configured:

Hibernate OGM can be used with JDK 7 too, but in this example we’ll be using Infinispan 8, which requires JDK 8.

Hibernate OGM is published in the Maven central repository.

Add org.hibernate.ogm:hibernate-ogm-bom:5.0.4.Final to your dependency management block and org.hibernate.ogm:hibernate-ogm-infinispan:5.0.4.Final to your project dependencies:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.hibernate.ogm</groupId>
            <artifactId>hibernate-ogm-bom</artifactId>
            <version>5.0.4.Final</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
<dependencyManagement>

<dependencies>
    <dependency>
        <groupId>org.hibernate.ogm</groupId>
        <artifactId>hibernate-ogm-infinispan</artifactId>
    </dependency>
</dependencies>

The former is a so-called "bill of materials" POM which specifies a matching set of versions for Hibernate OGM and its dependencies. That way you never need to specify a version explicitly within your dependencies block, you will rather get the versions from the BOM automatically.

We will use the JPA APIs in this tutorial. While Hibernate OGM depends on JPA 2.1, it is marked as provided in the Maven POM file. If you run outside a Java EE container, make sure to explicitly add the dependency:

<dependency>
    <groupId>org.hibernate.javax.persistence</groupId>
    <artifactId>hibernate-jpa-2.1-api</artifactId>
</dependency>

Let’s now map our first Hibernate OGM entity.

@Entity
public class Dog {
   @Id @GeneratedValue(strategy = GenerationType.TABLE, generator = "dog")
   @TableGenerator(
      name = "dog",
      table = "sequences",
      pkColumnName = "key",
      pkColumnValue = "dog",
      valueColumnName = "seed"
   )
   public Long getId() { return id; }
   public void setId(Long id) { this.id = id; }
   private Long id;

   public String getName() { return name; }
   public void setName(String name) { this.name = name; }
   private String name;

   @ManyToOne
   public Breed getBreed() { return breed; }
   public void setBreed(Breed breed) { this.breed = breed; }
   private Breed breed;
}

@Entity
public class Breed {

   @Id @GeneratedValue(generator = "uuid")
   @GenericGenerator(name="uuid", strategy="uuid2")
   public String getId() { return id; }
   public void setId(String id) { this.id = id; }
   private String id;

   public String getName() { return name; }
   public void setName(String name) { this.name = name; }
   private String name;
}

I lied to you, we have already mapped two entities!

If you are familiar with JPA, you can see that there is nothing specific to Hibernate OGM in our mapping.

In this tutorial, we will use JBoss Transactions for our JTA transaction manager. So let’s add the JTA API and JBoss Transactions to our POM as well. The final list of dependencies should look like this:

<dependencies>
    <!-- Hibernate OGM Infinispan module; pulls in the OGM core module -->
    <dependency>
        <groupId>org.hibernate.ogm</groupId>
        <artifactId>hibernate-ogm-infinispan</artifactId>
    </dependency>

    <!-- standard APIs dependencies - provided in a Java EE container -->
    <dependency>
        <groupId>org.hibernate.javax.persistence</groupId>
        <artifactId>hibernate-jpa-2.1-api</artifactId>
    </dependency>
    <dependency>
        <groupId>org.jboss.spec.javax.transaction</groupId>
        <artifactId>jboss-transaction-api_1.2_spec</artifactId>
    </dependency>

    <!-- Add the Narayana Transactions Manager
         an implementation would be provided in a Java EE container,
         but this works nicely in Java SE as well -->
    <dependency>
        <groupId>org.jboss.narayana.jta</groupId>
        <artifactId>narayana-jta</artifactId>
    </dependency>
    <dependency>
        <groupId>org.jboss</groupId>
        <artifactId>jboss-transaction-spi</artifactId>
    </dependency>
</dependencies>

Next we need to define the persistence unit. Create a META-INF/persistence.xml file.

<?xml version="1.0"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
             version="2.0">

    <persistence-unit name="ogm-jpa-tutorial" transaction-type="JTA">
        <!-- Use the Hibernate OGM provider: configuration will be transparent -->
        <provider>org.hibernate.ogm.jpa.HibernateOgmPersistence</provider>
        <properties>
            <!-- Here you will pick which NoSQL technology to use, and configure it;
                 in this example we start a local in-memory Infinispan node. -->
            <property name="hibernate.ogm.datastore.provider" value="infinispan"/>
        </properties>
    </persistence-unit>
</persistence>

Let’s now persist a set of entities and retrieve them.

//accessing JBoss's Transaction can be done differently but this one works nicely
TransactionManager tm = com.arjuna.ats.jta.TransactionManager.transactionManager();

//build the EntityManagerFactory as you would build in in Hibernate ORM
EntityManagerFactory emf = Persistence.createEntityManagerFactory(
    "ogm-jpa-tutorial");

final Logger logger = LoggerFactory.getLogger(DogBreedRunner.class);

[..]

//Persist entities the way you are used to in plain JPA
tm.begin();
logger.infof("About to store dog and breed");
EntityManager em = emf.createEntityManager();
Breed collie = new Breed();
collie.setName("Collie");
em.persist(collie);
Dog dina = new Dog();
dina.setName("Dina");
dina.setBreed(collie);
em.persist(dina);
Long dinaId = dina.getId();
em.flush();
em.close();
tm.commit();

[..]

//Retrieve your entities the way you are used to in plain JPA
tm.begin();
logger.infof("About to retrieve dog and breed");
em = emf.createEntityManager();
dina = em.find(Dog.class, dinaId);
logger.infof("Found dog %s of breed %s", dina.getName(), dina.getBreed().getName());
em.flush();
em.close();
tm.commit();

[..]

emf.close();

A working example can be found in Hibernate OGM’s distribution under hibernate-ogm-documentation/examples/gettingstarted.

What have we seen?

  • Hibernate OGM is a JPA implementation and is used as such both for mapping and in API usage
  • It is configured as a specific JPA provider: org.hibernate.ogm.jpa.HibernateOgmPersistence

Let’s explore more in the next chapters.

Note

Hibernate OGM defines an abstraction layer represented by DatastoreProvider and GridDialect to separate the OGM engine from the datastores interaction. It has successfully abstracted various key/value stores, document stores and graph databases. We are working on testing it on other NoSQL families.

In this chapter we will explore:

  • the general architecture
  • how the data is persisted in the NoSQL datastore
  • how we support JP-QL queries

Let’s start with the general architecture.

Hibernate OGM is made possible by the reuse of a few key components:


Hibernate OGM reuses as much as possible from the Hibernate ORM infrastructure. There is no need to rewrite a new JPA engine. The Persisters and the Loaders (two interfaces used by Hibernate ORM) have been rewritten to persist data in the NoSQL store. These implementations are the core of Hibernate OGM. We will see in Section 3.2, “How is data persisted” how the data is structured.

The particularities between NoSQL stores are abstracted by the notion of a DatastoreProvider and a GridDialect.

  • DatastoreProvider abstracts how to start and maintain a connection between Hibernate OGM and the datastore.
  • GridDialect abstracts how data itself including association is persisted.

Think of them as the JDBC layer for our NoSQL stores.

Other than these, all the Create/Read/Update/Delete (CRUD) operations are implemented by the Hibernate ORM engine (object hydration and dehydration, cascading, lifecycle etc).

As of today, we have implemented the following datastore providers:

  • a HashMap based datastore provider (for testing)
  • an Infinispan based datastore provider to persist your entities in Infinispan
  • an Ehcache based datastore provider to persist your entities in Ehcache
  • a MongoDB based datastore provider to persist data in a MongoDB database
  • a Neo4j based datastore provider to persist data in the Neo4j graph database
  • a CouchDB based datastore provider to persist data in the CouchDB document store (experimental)
  • a Cassandra based datastore provider to persist data in Apache Cassandra (experimental)
  • a Redis based datastore provider to persist data in the Redis key/value store (experimental)

To implement JP-QL queries, Hibernate OGM parses the JP-QL string and calls the appropriate translator functions to build a native query. If the underlying engine does not have any query support, we use Hibernate Search as an external query engine.

We will discuss the subject of querying in more details in Section 3.4, “How is data queried”.

Hibernate OGM best works in a JTA environment. The easiest solution is to deploy it on a Java EE container. Alternatively, you can use a standalone JTA TransactionManager. We explain how to in Section 4.2.2, “In a standalone JTA environment”.

Let’s now see how and in which structure data is persisted in the NoSQL data store.

Hibernate OGM tries to reuse as much as possible the relational model concepts, at least when they are practical and make sense in OGM’s case. For very good reasons, the relational model brought peace in the database landscape over 30 years ago. In particular, Hibernate OGM inherits the following traits:

If the application data model is too tightly coupled with your persistent data model, a few issues arise:

Entities are stored as tuples of values by Hibernate OGM. More specifically, each entity is conceptually represented by a Map<String,Object> where the key represents the column name (often the property name but not always) and the value represents the column value as a basic type. We favor basic types over complex ones to increase portability (across platforms and across type / class schema evolution over time). For example a URL object is stored as its String representation.

The key identifying a given entity instance is composed of:


The GridDialect specific to the NoSQL datastore you target is then responsible to convert this map into the most natural model:

  • for a key/value store or a data grid, we use the logical key as the key in the grid and we store the map as the value. Note that it’s an approximation and some key/value providers will use more tailored approaches.
  • for a document oriented store, the map is represented by a document and each entry in the map corresponds to a property in a document.

Associations are also stored as tuples. Hibernate OGM stores the information necessary to navigate from an entity to its associations. This is a departure from the pure relational model but it ensures that association data is reachable via key lookups based on the information contained in the entity tuple we want to navigate from. Note that this leads to some level of duplication as information has to be stored for both sides of the association.

The key in which association data are stored is composed of:

  • the table name
  • the column name(s) representing the foreign key to the entity we come from
  • the column value(s) representing the foreign key to the entity we come from

Using this approach, we favor fast read and (slightly) slower writes.


Note that this approach has benefits and drawbacks:

  • it ensures that all CRUD operations are doable via key lookups
  • it favors reads over writes (for associations)
  • but it duplicates data

Again, there are specificities in how data is inherently stored in the specific NoSQL store. For example, in document oriented stores, the association information including the identifier to the associated entities can be stored in the entity owning the association. This is a more natural model for documents.


Some identifiers require to store a seed in the datastore (like sequences for examples). The seed is stored in the value whose key is composed of:

  • the table name
  • the column name representing the segment
  • the column value representing the segment

Warning

This description is how conceptually Hibernate OGM asks the datastore provider to store data. Depending on the family and even the specific datastore, the storage is optimized to be as natural as possible. In other words as you would have stored the specific structure naturally. Make sure to check the chapter dedicated to the NoSQL store you target to find the specificities.

Many NoSQL stores have no notion of schema. Likewise, the tuple stored by Hibernate OGM is not tied to a particular schema: the tuple is represented by a Map, not a typed Map specific to a given entity type. Nevertheless, JPA does describe a schema thanks to:

  • the class schema
  • the JPA physical annotations like @Table and @Column.

While tied to the application, it offers some robustness and explicit understanding when the schema is changed as the schema is right in front of the developers' eyes. This is an intermediary model between the strictly typed relational model and the totally schema-less approach pushed by some NoSQL families.

Since Hibernate OGM wants to offer all of JPA, it needs to support JP-QL queries. Hibernate OGM parses the JP-QL query string and extracts its meaning. From there, several options are available depending of the capabilities of the NoSQL store you target:

If the NoSQL datastore has some query capabilities and if the JP-QL query is simple enough to be executed by the datastore, then the JP-QL parser directly pushes the query generation to the NoSQL specific query translator. The query returns the list of matching entity columns or projections and Hibernate OGM returns managed entities.

Some NoSQL stores have poor query support, or none at all. In this case Hibernate OGM can use Hibernate Search as its indexing and query engine. Hibernate Search is able to index and query objects - entities - and run full-text queries. It uses the well known Apache Lucene to do this but adds a few interesting characteristics like clustering support and an object oriented abstraction including an object oriented query DSL. Let’s have a look at the architecture of Hibernate OGM when using Hibernate Search:


In this situation, Hibernate ORM Core pushes change events to Hibernate Search which will index entities accordingly and keep the index and the datastore in sync. The JP-QL query parser delegates the query translation to the Hibernate Search query translator and executes the query on top of the Lucene indexes. Indexes can be stored in various fashions:

  • on a file system (the default in Lucene)
  • in Infinispan via the Infinispan Lucene directory implementation: the index is then distributed across several servers transparently
  • in NoSQL stores that can natively store Lucene indexes
  • in NoSQL stores that can be used as overflow to Infinispan: in this case Infinispan is used as an intermediary layer to serve the index efficiently but persists the index in another NoSQL store.

Tip

You can use Hibernate Search even if you do plan to use the NoSQL datastore query capabilities. Hibernate Search offers a few interesting options:

  • clusterability
  • full-text queries - ie Google for your entities
  • geospatial queries
  • query faceting (ie dynamic categorization of the query results by price, brand etc)

Hibernate OGM favors ease of use and convention over configuration. This makes its configuration quite simple by default.

Hibernate OGM can be used via the Hibernate native APIs (Session) or via the JPA APIs (EntityManager). Depending of your choice, the bootstrapping strategy is slightly different.

If you use JPA as your primary API, the configuration is extremely simple. Hibernate OGM is seen as a persistence provider which you need to configure in your persistence.xml. That’s it! The provider name is org.hibernate.ogm.jpa.HibernateOgmPersistence.


There are a couple of things to notice:

You also need to configure which NoSQL datastore you want to use and how to connect to it. We will detail how to do that later in Chapter 8, NoSQL datastores.

In this case, we have used the defaults settings for Infinispan: this will start a local, in-memory Infinispan instance which is useful for testing but the stored data will be lost on shutdown. You might think of this configuration as similar to storing your data in an hashmap.

From there, simply bootstrap JPA the way you are used to with Hibernate ORM:

  • via Persistence.createEntityManagerFactory
  • by injecting the EntityManager / EntityManagerFactory in a Java EE container
  • by using your favorite injection framework (CDI - Weld, Spring, Guice)

Note

Note that what you’re starting is not an exotic new JPA implementation but is in all effects an instance of Hibernate ORM, although using some alternative internal components to deal with the NoSQL stores. This means that any framework and tool integrating with Hibernate ORM can integrate with Hibernate OGM - of course as long as it’s not making assumptions such as that a JDBC datasource will be used.

If you want to bootstrap Hibernate OGM using the native Hibernate APIs, use the new bootstrap API from Hibernate ORM 5. By setting OgmProperties.ENABLED to true, the Hibernate OGM components will be activated. Note that unwrapping into OgmSessionFactoryBuilder is not strictly needed, but it will allow you to set Hibernate OGM specific options in the future and also gives you a reference to OgmSessionFactory instead of SessionFactory.


There are a couple of things to notice:

You also need to configure which NoSQL datastore you want to use and how to connect to it. We will detail how to do that later in Chapter 8, NoSQL datastores. In this case, we have used the defaults settings for Infinispan.

Hibernate OGM runs in various environments: it should work pretty much in all environments in which Hibernate ORM runs. There are however some selected environments in which it was tested more thoroughly than others. The current version is being tested regularly in Java SE (without a container) and within the WildFly 10 application server; at time of writing this there’s no known reason for it to not work in different containers as long as you remember that it requires a specific version of Hibernate ORM: some containers might package a conflicting version.

You don’t have to do much in this case. You need three specific settings:

If you use JPA, simply set the transaction-type to JTA and the transaction factory will be set for you.

If you use Hibernate ORM native APIs only, then set hibernate.transaction.coordinator_class to "jta".

Set the JTA platform to the right Java EE container. The property is hibernate.transaction.jta.platform and must contain the fully qualified class name of the lookup implementation. The list of available values are listed in Hibernate ORM’s configuration section. For example in WildFly 10 you would pick JBossAS, although in WildFly these settings are automatically injected so you could skip this.

In your persistence.xml you usually need to define an existing datasource. This is not needed by Hibernate OGM: it will ignore the datasource, but JPA specification mandates the setting.


java:DefaultDS will work for out of the box WildFly deployments.

There is a set of common misconceptions in the Java community about JTA:

None of these are true: let me show you how to use the Narayana Transactions Manager in a standalone environment with Hibernate OGM.

In Hibernate OGM, make sure to set the following properties:

Add the Narayana Transactions Manager to your classpath. If you use maven, it should look like this:


The next step is you get access to the transaction manager. The easiest solution is to do as the following example:

TransactionManager transactionManager =
   com.arjuna.ats.jta.TransactionManager.transactionmanager();

Then use the standard JTA APIs to demarcate your transaction and you are done!


That was not too hard, was it? Note that application frameworks like the Spring Framework should be able to initialize the transaction manager and call it to demarcate transactions for you. Check their respective documentation.

The most important options when configuring Hibernate OGM are related to the datastore. They are explained in Chapter 8, NoSQL datastores.

Otherwise, most options from Hibernate ORM and Hibernate Search are applicable when using Hibernate OGM. You can pass them as you are used to do either in your persistence.xml file, your hibernate.cfg.xml file or programmatically.

More interesting is a list of options that do not apply to Hibernate OGM and that should not be set:

  • hibernate.dialect
  • hibernate.connection.* and in particular hibernate.connection.provider_class
  • hibernate.show_sql and hibernate.format_sql
  • hibernate.default_schema and hibernate.default_catalog
  • hibernate.use_sql_comments
  • hibernate.jdbc.*
  • hibernate.hbm2ddl.auto and hibernate.hbm2ddl.import_file

Provided you’re deploying on WildFly, there is an additional way to add the OGM dependencies to your application.

In WildFly, class loading is based on modules; this system defines explicit, non-transitive dependencies on other modules.

Modules allow to share the same artifacts across multiple applications, making deployments smaller and quicker, and also making it possible to deploy multiple different versions of any library.

More details about modules are described in Class Loading in WildFly.

When deploying a JPA application on WildFly, you should be aware that there are some additional useful configuration properties defined by the WildFly JPA subsystem. These are documented in WildFly JPA Reference Guide.

If you apply the following instructions you can create small and efficient deployments which do not include any dependency, as you can include your favourite version of Hibernate OGM directly to the collection of container provided libraries.

You can download the pre-packaged module ZIP for this version of Hibernate OGM from:

Unpack the archive into the modules folder of your WildFly 10 installation. The modules included are:

  • org.hibernate.ogm, the core Hibernate OGM library.
  • org.hibernate.ogm.<%DATASTORE%>, one module for each datastore, with <%DATASTORE%> being one of infinispan, mongodb etc.
  • Several shared dependencies such as org.hibernate.hql:<%VERSION%> (containing the query parser) and others

The module slot to use for Hibernate OGM 5.0.4.Final is 5.0 as the format of the slot name does not include the "micro" part of the project version.

There are two ways to include the dependencies in your project:

Using the manifest
Add this entry to the MANIFEST.MF in your archive (replace <%DATASTORE%> with the right value for your chosen datastore):
Dependencies: org.hibernate.ogm:5.0 services, org.hibernate.ogm.<%DATASTORE%>:5.0 services
Using jboss-deployment-structure.xml
This is a JBoss-specific descriptor. Add a WEB-INF/jboss-deployment-structure.xml in your archive with the following content (replace <%DATASTORE%> with the right value for your chosen datastore):
<jboss-deployment-structure>
    <deployment>
        <dependencies>
            <module name="org.hibernate.ogm" slot="5.0" services="export" />
            <module name="org.hibernate.ogm.<%DATASTORE%>" slot="5.0" services="export" />
        </dependencies>
    </deployment>
</jboss-deployment-structure>

More information about the descriptor can be found in the WildFly documentation.

A compatible Hibernate Search module is included in WildFly 10, and Hibernate Search is activated automatically if you’re indexing any entity.

When using WildFly several of the technologies it includes are automatically enabled. For example Hibernate ORM is made available to your applications if your persistence.xml defines a persistence unit using Hibernate as persistence provider (or is not specifying any provider, as Hibernate is the default one).

Similarly, Hibernate Search is automatically activated and made available on the user’s application classpath if and when the application server detects the need for it. This is the default behaviour, but you are in control and can override this all; see the WildFly JPA Reference Guide for a full list of properties you can explicitly set. Among these you fill find properties to control and override which modules are activated.

Hibernate OGM however is currently not included in WildFly, so you have to enable it explicitly.

Optionally you could download a different version of the Hibernate Search modules, provided it is compatible with the Hibernate OGM version you plan to use. For example you might want to download a more recent micro version of what is included in WildFly 10 at the time of publishing this documentation.

The Hibernate Search documentation explains the details of downloading and deploying a custom version: Update and activate latest Hibernate Search version in WildFly.

This approach might require you to make changes to the XML definitions of the Hibernate OGM modules to change the references to the Hibernate Search slot to the slot version that you plan to use.

This section mainly describes the specificities of Hibernate OGM mappings. It’s not meant to be a comprehensive guide to entity mappings, the complete guide is Hibernate ORM’s documentation: after all Hibernate OGM is Hibernate ORM.

Pretty much all entity related constructs should work out of the box in Hibernate OGM. @Entity, @Table, @Column, @Enumarated, @Temporal, @Cacheable and the like will work as expected. If you want an example, check out Chapter 2, Getting started with Hibernate OGM or the documentation of Hibernate ORM. Let’s concentrate of the features that differ or are simply not supported by Hibernate OGM.

Hibernate OGM supports the following inheritance strategies: * InheritanceType.TABLE_PER_CLASS * InheritanceType.SINGLE_TABLE

If you feel the need to support other strategies, let us know (see Section 1.2, “How to contribute”).

JPA annotations refer to tables but the kind of abstraction the database will use depends on the nature of the NoSQL datastore you are dealing with. For example, in MongoDB a table is mapped as a document.

You can find more details about the way entities are stored in the corresponding mapping section of the datastore you are using.

Secondary tables are not supported by Hibernate OGM at the moment. If you have needs for this feature, let us know (see Section 1.2, “How to contribute”).

Queries are partially supported, you will find more information in the query chapter.

All standard JPA id generators are supported: IDENTITY, SEQUENCE, TABLE and AUTO. If you need support for additional generators, let us know (see Section 1.2, “How to contribute”).

Note

Some NoSQL databases can not provide an efficient implementation for IDENTITY or SEQUENCE, for these cases we recommend you use a UUID based generator. For example on Infinispan using IDENTITY is possible but it will require using cluster wide coordination to maintain the counters, which is not going to perform very well.

@Entity
public class Breed {

    @Id @GeneratedValue(generator = "uuid")
    @GenericGenerator(name="uuid", strategy="uuid2")
    public String getId() { return id; }
    public void setId(String id) { this.id = id; }
    private String id;

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    private String name;
}

Hibernate OGM has very few specific APIs. For the most part, you will interact with it via either:

  • the JPA APIs
  • the native Hibernate ORM APIs

This chapter will only discuss the Hibernate OGM specific behaviors regarding these APIs. If you need to learn JPA or the native Hibernate APIs, check out the Hibernate ORM documentation.

We already discussed this subject earlier, have a look at Chapter 4, Configure and start Hibernate OGM for all the details.

As a reminder, it basically boils down to either:

  • set the right persistence provider in your persistence.xml file and create an EntityManagerFactory the usual way
  • start via the Hibernate ORM native APIs using StandardServiceRegistryBuilder and MetadataSources to boot a SessionFactory

You know of the Java Persistence and Hibernate ORM native APIs? You are pretty much good to go. If you need a refresher, make sure you read the Hibernate ORM documentation.

A few things are a bit different though, let’s discuss them.

Most of the EntityManager and Session contracts are supported. Here are the few exceptions:

  • Session.createCriteria: criteria queries are not yet supported in Hibernate OGM
  • Session.createFilter: queries on collections are not supported yet
  • Session 's enableFilter, disableFilter etc: query filters are not supported at the moment
  • doWork and doReturningWork are not implemented as they rely on JDBC connections - see OGM-694
  • Session 's stored procedure APIs are not supported
  • Session 's natural id APIs are not yet supported
  • Session.lock is not fully supported at this time
  • EntityManager 's criteria query APIs are not supported
  • EntityManager 's stored procedure APIs are not supported - see OGM-695
  • EntityManager.lock is not fully supported at this time
  • see Chapter 7, Query your entities to know what is supported for JP-QL and native queries

Even though some underlying NoSQL datastores do not support transaction, it is important to demarcate transaction via the Hibernate OGM APIs. Let’s see why.

Hibernate does pile up changes for as long as it can before pushing them down to the datastore. This opens up the doors to huge optimizations (avoiding duplication, batching operations etc). You can force changes to be sent to the datastore by calling Session.flush or EntityManager.flush. In some situations - for example before some queries are executed -, Hibernate will flush automatically. It will also flush when the transaction demarcation happens (whether there is a real transaction or not).

The best approach is to always demarcate the transaction as shown below. This avoids the needs to manually call flush and will offer future opportunities for Hibernate OGM.


If an error occurs during flushing a set of changes, some data changes may already have been applied in the datastore. If the store is non-transactional, there is no way to rollback (undo) these changes if they were already flushed. In this case it is desirable to know which changes have been applied and which ones failed in order to take appropriate action.

Hibernate OGM provides an error compensation API for this purpose. By implementing the org.hibernate.ogm.failure.ErrorHandler interface, you will be notified if

Use cases for the error compensation API include:

In its current form the API lays the ground for manually performing these and similar tasks, but we envision a more automated approach in future versions, e.g. for automatic retries of failed operations or the automatic application of compensating operations.

Let’s take a look at an example:


The onRollback() method - which is called when the transaction is rolled back (either by the user or by the container) - shows how to iterate over all methods applied prior to the rollback, examine their specific type and e.g. write them to a log file.

The onFailedGridDialectOperation() method is called for each specific datastore operation failing. It lets you decide whether to continue ignoring the failure, retry or abort the operation. If ABORT is returned, the causing exception will be re-thrown, eventually causing the current transaction to be rolled back. If CONTINUE is returned, that exception will be ignored, causing the current transaction to continue.

The decision whether to abort or continue can be based on the specific exception type or on the grid dialect operation which caused the failure. In the example all exceptions of type TupleAlreadyExistsException are ignored, whereas all other exceptions cause the current flush cycle to be aborted. You also could react to datastore-specific exceptions such as MongoDB’s MongoTimeoutException, if needed.

Note that by extending the provided base class BaseErrorHandler rather than implementing the interface directly, you only need to implement those callback methods you are actually interested in. The implementation will also not break if further callback methods are added to the ErrorHandler interface in future releases.

Having implemented the error handler, it needs to be registered with Hibernate OGM. To do so, specify it using the property hibernate.ogm.error_handler, e.g. as a persistence unit property in META-INF/persistence.xml:

<property name="hibernate.ogm.error_handler" value="com.example.ExampleErrorHandler"/>

Once your data is in the datastore, it’s time for some query fun! With Hibernate OGM, you have a few alternatives that should get you covered:

  • Use JP-QL - only for simple queries for now
  • Use the NoSQL native query mapping the result as managed entities
  • Use Hibernate Search queries - primarily full-text queries

For Hibernate OGM, we developed a brand new JP-QL parser which is already able to convert simple queries into the native underlying datastore query language (e.g. MongoQL for MongoDB, CypherQL for Neo4J, etc). This parser can also generate Hibernate Search queries for datastores that do not support a query language.

You can make use of the following JP-QL constructs:

In particular and of notice, what is not supported is:

That may sound rather limiting for your use cases so bear with us. This is a hot area we want to improve, please tell us what feature you miss by opening a JIRA or via email. Also read the next section, you will see other alternatives to implement your queries.

Let’s look at some of the queries you can express in JP-QL:


There are also features that are partially supported:

  • Inner JOIN on an embedded association: works as expected with Neo4j and MongoDB; doesn’t work if your datastore provider implements JP-QL queries using Hibernate Search.
  • Projections or filters on properties of an embedded identifier: works as expected with Neo4j and MongoDB; doesn’t work if your datastore provider implements JP-QL queries using Hibernate Search.

These are better illustrated by the following example:

Example 7.2. Entity with embedded collection and supported JP-QL queries

@Indexed
@Entity
public class StoryGame {

    @DocumentId
    @EmbeddedId
    @FieldBridge(impl = NewsIdFieldBridge.class)
    private StoryID storyId;

    @ElementCollection
    @IndexedEmbedded
    private List<OptionalStoryBranch> optionalEndings;

    ...

}

@Embeddable
public class StoryID implements Serializable {

    private String title;
    private String author;

    ...
}

@Embeddable
public class OptionalStoryBranch {

    // Analyze.NO for filtering in query
    // Store.YES for projection in query
    @Field(store = Store.YES, analyze = Analyze.NO)
    private String text;

    ...

}

Filter the results using the supported operators will work for all the datastores:

String query =
    "SELECT sg" +
    "FROM StoryGame sg JOIN sg.optionalEndings ending WHERE ending.text = 'Happy ending'"
List<StoryGame> stories = session.createQuery( query ).list();

Projection of properties of an embedded association works with Neo4j and MongoDB, but the other datastores will only return one element from the association. This is due to the fact that Hibernate Search is currently not supporting projection of associations. Here’s an example of a query affected by this:

String query =
     "SELECT ending.text " +
     "FROM StoryGame sg JOIN sg.optionalEndings ending WHERE ending.text LIKE 'Happy%'";
List<String> endings = session.createQuery( query ).list();

Projecting and filtering on embedded id properties works with Neo4j and MongoDB but throws an exception with the other datastores:

String query =
     "SELECT sg.storyId.title FROM StoryGame sg WHERE sg.storyId.title = 'Best Story Ever'";
List<String> title = session.createQuery( query ).list();

It will cause the following exception if the datastore uses Hibernate Search to execute JP-QL queries:

org.hibernate.hql.ParsingException: HQL100002: The type [storyId] has no indexed property named title.

Note

In order to reflect changes performed in the current session, all entities affected by a given query are flushed to the datastore prior to query execution (that’s the case for Hibernate ORM as well as Hibernate OGM).

For not fully transactional stores, this can cause changes to be written as a side-effect of running queries which cannot be reverted by a possible later rollback.

Depending on your specific use cases and requirements you may prefer to disable auto-flushing, e.g. by invoking query.setFlushMode(FlushMode.MANUAL). Bear in mind though that query results will then not reflect changes applied within the current session.

Often you want the raw power of the underlying NoSQL query engine. Even if that costs you portability.

Hibernate OGM addresses that problem by letting you express native queries (e.g. in MongoQL or CypherQL) and map the result of these queries as mapped entities.

In JPA, use EntityManager.createNativeQuery. The first form accepts a result class if your result set maps the mapping definition of the entity. The second form accepts the name of a resultSetMapping and lets you customize how properties are mapped to columns by the query. You can also used a predefined named query which defines its result set mapping.

Let’s take a look at how it is done for Neo4J:


In the native Hibernate API, use OgmSession.createNativeQuery or Session.getNamedQuery. The former form lets you define the result set mapping programmatically. The latter is receiving the name of a predefined query already describing its result set mapping.


Check out each individual datastore chapter for more info on the specifics of the native query language mapping. In particular Neo4J and MongoDB.

Hibernate Search offers a way to index Java objects into Lucene indexes and to execute full-text queries on them. The indexes do live outside your datastore. This offers a few interesting properties in terms of feature set and scalability.

Apache Lucene is a full-text indexing and query engine with excellent query performance. Feature wise, full-text means you can do much more than a simple equality match.

Hibernate Search natively integrates with Hibernate ORM. And Hibernate OGM of course!


Assuming our database contains an Hypothesis instance having description "Sometimes tomorrow we release", that instance will be returned by our full-text query.

Text similarity can be very powerful as it can be configured for specific languages or domain specific terminology; it can deal with typos and synonyms, and above all it can return results by relevance.

Worth noting the Lucene index is a vectorial space of term occurrence statistics: so extracting tags from text, frequencies of strings and correlate this data makes it very easy to build efficient data analysis applications.

While the potential of Lucene queries is very high, it’s not suited for all use cases Let’s see some of the limitations of Lucene Queries as our main query engine:

  • Lucene doesn’t support Joins. Any to-One relations can be mapped fine, and the Lucene community is making progress on other forms, but restrictions on OneToMany or ManyToMany can’t be implemented today.
  • Since we apply changes to the index at commit time, your updates won’t affect queries until you commit (we might improve on this).
  • While queries are extremely fast, write operations are not as fast (but we can make it scale).

For a complete understanding of what Hibernate Search can do for you and how to use it, go check the Hibernate Search reference documentation.

Currently Hibernate OGM supports the following NoSQL datastores:

  • Map: stores data in an in-memory Java map to store data. Use it only for unit tests.
  • Infinispan: stores data into Infinispan (data grid)
  • Ehcache: stores data into Ehcache (cache)
  • MongoDB: stores data into MongoDB (document store)
  • Neo4j: stores data into Neo4j (graph database)
  • CouchDB: stores data into CouchDB (document store)

    • at this stage, this datastore is experimental
  • Redis: stores data into Redis (key-value store)

    • at this stage, this datastore is experimental

More are planned, if you are interested, come talk to us (see Chapter 1, How to get help and contribute on Hibernate OGM).

For each datastore, Hibernate OGM has specific integration code called a datastore provider. All are in a dedicated maven module, you simply need to depend on the one you use.

Hibernate OGM interacts with NoSQL datastores via two contracts:

  • a DatastoreProvider which is responsible for starting and stopping the connection(s) with the datastore and prop up the datastore if needed
  • a GridDialect which is responsible for converting an Hibernate OGM operation into a datastore specific operation

Only a few steps are necessary:

Adding the relevant Hibernate OGM module in your classpath looks like this in Maven:

<dependency>
    <groupId>org.hibernate.ogm</groupId>
    <artifactId>hibernate-ogm-infinispan</artifactId>
    <version>5.0.4.Final</version>
</dependency>

The module names are hibernate-ogm-infinispan, hibernate-ogm-ehcache, hibernate-ogm-mongodb, hibernate-ogm-neo4j, hibernate-ogm-couchdb, hibernate-ogm-redis and hibernate-ogm-cassandra. The map datastore is included in the Hibernate OGM engine module.

Next, configure which datastore provider you want to use. This is done via the hibernate.ogm.datastore.provider option. Possible values are:

By default, a datastore provider chooses the grid dialect transparently but you can override this setting with the hibernate.ogm.datastore.grid_dialect option. Use the fully qualified class name of the GridDialect implementation. Most users should ignore this setting entirely.

Let’s now look at the specifics of each datastore provider. How to configure it further, what mapping structure is used and more.

Infinispan is an open source in-memory data grid focusing on high performance. As a data grid, you can deploy it on multiple servers - referred to as nodes - and connect to it as if it were a single storage engine: it will cleverly distribute both the computation effort and the data storage.

It is trivial to setup on a single node, in your local JVM, so you can easily try Hibernate OGM. But Infinispan really shines in multiple node deployments: you will need to configure some networking details but nothing changes in terms of application behaviour, while performance and data size can scale linearly.

From all its features we will only describe those relevant to Hibernate OGM; for a complete description of all its capabilities and configuration options, refer to the Infinispan project documentation at infinispan.org.

You configure Hibernate OGM and Infinispan in two steps basically:

The advanced configuration details of an Infinispan Cache are defined in an Infinispan specific XML configuration file; the Hibernate OGM properties are simple and usually just point to this external resource.

To use the default configuration provided by Hibernate OGM - which is a good starting point for new users - you don’t have to set any property.

Depending on the cache mapping approach, Hibernate OGM will either:

The preferred strategy is CACHE_PER_TABLE as it offers both more fine grained configuration options and the ability to work on specific entities in a more simple fashion.

In the following paragraphs, we will explain which aspects of Infinispan you’re likely to want to reconfigure from their defaults. All attributes and elements from Infinispan which we don’t mention are safe to ignore. Refer to the Infinispan User Guide for the guru level performance tuning and customizations.

An Infinispan configuration file is an XML file complying with the Infinispan schema; the basic structure is shown in the following example:


There are global settings that can be set before the cache_container section. These settings will affect the whole instance; mainly of interest for Hibernate OGM users is the jgroups element in which we will set JGroups configuration overrides.

Inside the cache-container section are defined explicit named caches and their configurations as well as the default cache (named DEFAULT here) if we want to affect all named caches. This is where we will likely want to configure clustering modes, eviction policies and CacheStores.

In its default configuration Infinispan stores all data in the heap of the JVM; in this barebone mode it is conceptually not very different than using a HashMap: the size of the data should fit in the heap of your VM, and stopping/killing/crashing your application will get all data lost with no way to recover it.

To store data permanently (out of the JVM memory) a CacheStore should be enabled. The Infinispan project provides many CacheStore implementations; a simple one is the "single file store" which is able to store data in simple binary files, on any read/write mounted filesystem; You can find many more implementations to store your data in anything from JDBC connected relational databases, other NoSQL engines such as MongoDB and Cassandra, or even delegate to other Infinispan clusters. Finally, implementing a custom CacheStore is quite easy.

To limit the memory consumption of the precious heap space, you can activate a passivation or an eviction policy; again there are several strategies to play with, for now let’s just consider you’ll likely need one to avoid running out of memory when storing too many entries in the bounded JVM memory space; of course you don’t need to choose one while experimenting with limited data sizes: enabling such a strategy doesn’t have any other impact in the functionality of your Hibernate OGM application (other than performance: entries stored in the Infinispan in-memory space is accessed much quicker than from any CacheStore).

A CacheStore can be configured as write-through, committing all changes to the CacheStore before returning (and in the same transaction) or as write-behind. A write-behind configuration is normally not encouraged in storage engines, as a failure of the node implies some data might be lost without receiving any notification about it, but this problem is mitigated in Infinispan because of its capability to combine CacheStore write-behind with a synchronous replication to other Infinispan nodes.


In this example we enabled both eviction and a CacheStore (the persistence element). LIRS is one of the choices we have for eviction strategies. Here it is configured to keep (approximately) 2000 entries in live memory and evict the remaining as a memory usage control strategy.

The CacheStore is enabling passivation, which means that the entries which are evicted are stored on the filesystem.

Warning

You could configure an eviction strategy while not configuring a passivating CacheStore! That is a valid configuration for Infinispan but will have the evictor permanently remove entries. Hibernate OGM will break in such a configuration.

The best thing about Infinispan is that all nodes are treated equally and it requires almost no beforehand capacity planning: to add more nodes to the cluster you just have to start new JVMs, on the same or different physical servers, having your same Infinispan configuration and your same application.

Infinispan supports several clustering cache modes; each mode provides the same API and functionality but with different performance, scalability and availability options:

To use the replication or distribution cache modes Infinispan will use JGroups to discover and connect to the other nodes.

In the default configuration, JGroups will attempt to autodetect peer nodes using a multicast socket; this works out of the box in the most network environments but will require some extra configuration in cloud environments (which often block multicast packets) or in case of strict firewalls. See the JGroups reference documentation, specifically look for Discovery Protocols to customize the detection of peer nodes.

Nowadays, the JVM defaults to use IPv6 network stack; this will work fine with JGroups, but only if you configured IPv6 correctly. It is often useful to force the JVM to use IPv4.

It is also important to let JGroups know which networking interface you want to use; it will bind to one interface by default, but if you have multiple network interfaces that might not be the one you expect.


Note

You don’t need to use IPv4: JGroups is compatible with IPv6 provided you have routing properly configured and valid addresses assigned.

The jgroups.bind_addr needs to match a placeholder name in your JGroups configuration in case you don’t use the default one.

The default configuration uses distribution as cache mode and uses the jgroups-tcp.xml configuration for JGroups, which is contained in the Infinispan jar as the default configuration for Infinispan users. Let’s see how to reconfigure this:

Example 9.4. Reconfiguring cache mode and override JGroups configuration

<?xml version="1.0" encoding="UTF-8"?>
<infinispan
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="urn:infinispan:config:7.0 http://www.infinispan.org/schemas/infinispan-config-7.0.xsd"
    xmlns="urn:infinispan:config:7.0">

    <jgroups>
        <stack-file name="custom-stack" path="my-jgroups-conf.xml" />
    </jgroups>

    <cache-container name="HibernateOGM" default-cache="DEFAULT">
        <transport stack="custom-stack" />

        <!-- *************************************** -->
        <!--     Default cache used as template      -->
        <!-- *************************************** -->
        <distrubuted-cache name="DEFAULT" mode="SYNC">
            <locking striping="false" acquire-timeout="10000"
                concurrency-level="500" write-skew="false" />
            <transaction mode="NON_DURABLE_XA"
                transaction-manager-lookup="org.infinispan.transaction.lookup.JBossStandaloneJTAManagerLookup" />
            <state-transfer enabled="true" timeout="480000"
                await-initial-transfer="true" />
        </distributed-cache>

        <!-- Override the cache mode: -->
        <replicated-cache name="User" mode="SYNC">
            <locking striping="false" acquire-timeout="10000"
                concurrency-level="500" write-skew="false" />
            <transaction mode="NON_DURABLE_XA"
                transaction-manager-lookup="org.infinispan.transaction.lookup.JBossStandaloneJTAManagerLookup" />
            <state-transfer enabled="true" timeout="480000"
                await-initial-transfer="true" />
        </replicated-cache>

        <distributed-cache name="Order" mode="SYNC">
            <locking striping="false" acquire-timeout="10000"
                concurrency-level="500" write-skew="false" />
            <transaction mode="NON_DURABLE_XA"
                transaction-manager-lookup="org.infinispan.transaction.lookup.JBossStandaloneJTAManagerLookup" />
            <state-transfer enabled="true" timeout="480000"
                await-initial-transfer="true" />
        </distributed-cache>

        <distributed-cache name="associations_User_Order" mode="SYNC">
            <locking striping="false" acquire-timeout="10000"
                concurrency-level="500" write-skew="false" />
            <transaction mode="NON_DURABLE_XA"
                transaction-manager-lookup="org.infinispan.transaction.lookup.JBossStandaloneJTAManagerLookup" />
            <state-transfer enabled="true" timeout="480000"
                await-initial-transfer="true" />
        </distributed-cache>

    </cache-container>

</infinispan>

In the example above we specify a custom JGroups configuration file and set the cache mode for the default cache to distribution; this is going to be inherited by the Order and the associations_User_Order caches. But for User we have chosen (for the sake of this example) to use replication.

Now that you have clustering configured, start the service on multiple nodes. Each node will need the same configuration and jars.

Tip

We have just shown how to override the clustering mode and the networking stack for the sake of completeness, but you don’t have to!

Start with the default configuration and see if that fits you. You can fine tune these setting when you are closer to going in production.

To describe things simply, each entity is stored under a single key. The value itself is a map containing the columns / values pair.

Each association from one entity instance to (a set of) another is stored under a single key. The value contains the navigational information to the (set of) entity.

Entity identifiers are used to build the key in which the entity is stored in the cache.

The key is comprised of the following information:

In CACHE_PER_TABLE, the table name is inferred from the cache name. In CACHE_PER_KIND, the table name is necessary to identify the entity in the generic cache.



Since Infinispan has not native sequence nor identity column support, these are simulated using the table strategy, however their default values vary. We highly recommend you explicitly use a TABLE strategy if you want to generate a monotonic identifier.

But if you can, use a pure in-memory and scalable strategy like a UUID generator.


As you can see, in CACHE_PER_TABLE, the key does not contain the id source table name. It is inferred by the cache name hosting that key.



Entities are stored in the cache named after the entity name when using the CACHE_PER_TABLE strategy. In the CACHE_PER_KIND strategy, entities are stored in a single cache named ENTITIES.

The key is comprised of the following information:

In CACHE_PER_TABLE, the table name is inferred from the cache name. In CACHE_PER_KIND, the table name is necessary to identify the entity in the generic cache.

The entry value is an instance of org.infinispan.atomic.FineGrainedMap which contains all the entity properties - or to be specific columns. Each column name and value is stored as a key / value pair in the map. We use this specialized map as Infinispan is able to transport changes in a much more efficient way.


As you can see, the table name is not part of the key for CACHE_PER_TYPE. In the rest of this section we will no longer show the CACHE_PER_KIND strategy.




Here, we see that the collection of elements is stored in a separate cache and entry. The association key is made of:

  • the foreign key column names pointing to the owner of this association
  • the foreign key column values pointing to the owner of this association
  • the association table name in the CACHE_PER_KIND approach where all associations share the same cache

The association entry is a map containing the representation of each entry in the collection. The keys of that map are made of:

  • the names of the columns uniquely identifying that specific collection entry (e.g. for a Set this is all of the columns)
  • the values of the columns uniquely identifying that specific collection entry

The value attack to that collection entry key is a Map containing the key value pairs column name / column value.


Here we used an indexed collection and to identify the entry in the collection, only the owning entity id and the index value is enough.

Associations between entities are mapped like (collection of) embeddables except that the target entity is represented by its identifier(s).













Hibernate Search, which can be used for advanced query capabilities (see Chapter 7, Query your entities), needs some place to store the indexes for its embedded Apache Lucene engine.

A common place to store these indexes is the filesystem which is the default for Hibernate Search; however if your goal is to scale your NoSQL engine on multiple nodes you need to share this index. Network sharing file systems are a possibility but we don’t recommended that. Often the best option is to store the index in whatever NoSQL database you are using (or a different dedicated one).

Tip

You might find this section useful even if you don’t intend to store your data in Infinispan.

The Infinispan project provides an adaptor to plug into Apache Lucene, so that it writes the indexes in Infinispan and searches data in it. Since Infinispan can be used as an application cache to other NoSQL storage engines by using a CacheStore (see Section 9.2, “Manage data size”) you can use this adaptor to store the Lucene indexes in any NoSQL store supported by Infinispan:

  • JDBC databases
  • Cassandra
  • Filesystem (but locked correctly at the Infinispan level)
  • MongoDB
  • HBase
  • LevelDB
  • A secondary (independent) Infinispan grid

How to configure it? Here is a simple cheat sheet to get you started with this type of setup:

  • Add org.infinispan:infinispan-directory-provider:{infinispanVersion} to your dependencies
  • set these configuration properties:

    • hibernate.search.default.directory_provider = infinispan
    • hibernate.search.default.exclusive_index_use = false
    • hibernate.search.infinispan.configuration_resourcename = [infinispan configuration filename]

This configuration is simple and will work fine in most scenarios, but keep in mind that using 'exclusive_index_use' will be neither fast nor scalable. For high performance, high concurrency or production use please refer to the Infinispan documentation for more advanced configuration options and tuning.

The referenced Infinispan configuration should define a CacheStore to load/store the index in the NoSQL engine of choice. It should also define three cache names:


This configuration is not going to scale well on write operations: to do that you should read about the master/slave and sharding options in Hibernate Search. The complete explanation and configuration options can be found in the Hibernate Search Reference Guide

Some NoSQL support storage of Lucene indexes directly, in which case you might skip the Infinispan Lucene integration by implementing a custom DirectoryProvider for Hibernate Search. You’re very welcome to share the code and have it merged in Hibernate Search for others to use, inspect, improve and maintain.

When combined with Hibernate ORM, Ehcache is commonly used as a 2nd level cache to cache data whose primary storage is a relational database. When used with Hibernate OGM it is not "just a cache" but is used as the main (and exclusive) storage engine for your data.

This is not the reference manual for Ehcache itself: we’re going to list only how Hibernate OGM should be configured to use Ehcache; for all the tuning and advanced options please refer to the Ehcache Documentation.

This version of Hibernate OGM is compatible with Ehcache version 2.6.9. Other versions might work, but this is the only version which has been regularly tested with this version of Hibernate OGM.

Two steps:

Hibernate OGM expects you to define an Ehcache configuration in its own configuration resource; all what we need to set it the resource name.

To use the default configuration provided by Hibernate OGM - which is a good starting point for new users - you don’t have to set any property.

To describe things simply, each entity is stored under a single key. The value itself is a map containing the columns / values pair.

Each association from one entity instance to (a set of) another is stored under a single key. The value contains the navigational information to the (set of) entity.

Entity identifiers are used to build the key in which the entity is stored in the cache.

The key is comprised of the following information:

In CACHE_PER_TABLE, the table name is inferred from the cache name. In CACHE_PER_KIND, the table name is necessary to identify the entity in the generic cache.



Since Ehcache has not native sequence nor identity column support, these are simulated using the table strategy, however their default values vary. We highly recommend you explicitly use a TABLE strategy if you want to generate a monotonic identifier.

But if you can, use a pure in-memory and scalable strategy like a UUID generator.


As you can see, in CACHE_PER_TABLE, the key does not contain the id source table name. It is inferred by the cache name hosting that key.



Entities are stored in the cache named after the entity name when using the CACHE_PER_TABLE strategy. In the CACHE_PER_KIND strategy, entities are stored in a single cache named ENTITIES.

The key is comprised of the following information:

In CACHE_PER_TABLE, the table name is inferred from the cache name. In CACHE_PER_KIND, the table name is necessary to identify the entity in the generic cache.

The entry value is itself a map which contains all the entity properties - or to be specific columns. Each column name and value is stored as a key / value pair in the map.


As you can see, the table name is not part of the key for CACHE_PER_TYPE. In the rest of this section we will no longer show the CACHE_PER_KIND strategy.




Here, we see that the collection of elements is stored in a separate cache and entry. The association key is made of:

  • the foreign key column names pointing to the owner of this association
  • the foreign key column values pointing to the owner of this association
  • the association table name in the CACHE_PER_KIND approach where all associations share the same cache

The association entry is a map containing the representation of each entry in the collection. The keys of that map are made of:

  • the names of the columns uniquely identifying that specific collection entry (e.g. for a Set this is all of the columns)
  • the values of the columns uniquely identifying that specific collection entry

The value attack to that collection entry key is a Map containing the key value pairs column name / column value.


Here we used an indexed collection and to identify the entry in the collection, only the owning entity id and the index value is enough.

Associations between entities are mapped like (collection of) embeddables except that the target entity is represented by its identifier(s).













MongoDB is a document oriented datastore written in C++ with strong emphasis on ease of use. The nested nature of documents make it a particularly natural fit for most object representations.

This implementation is based upon the MongoDB Java driver.

We currently support version 3.3.0 and 3.2.

Configuring Hibernate OGM to use MongoDb is easy:

To get started quickly, pay attention to the following options:

And we should have you running. The following properties are available to configure MongoDB support:

MongoDB datastore configuration properties

hibernate.ogm.datastore.provider
To use MongoDB as a datastore provider, this property must be set to mongodb
hibernate.ogm.option.configurator
The fully-qualified class name or an instance of a programmatic option configurator (see Section 11.1.5, “Programmatic configuration”)
hibernate.ogm.datastore.host

The hostname and port of the MongoDB instance. The optional port is concatenated to the host and separated by a colon. When using replica sets, you can define the various servers in a comma separated list of hosts and ports. Let’s see a few valid examples:

  • mongodb.example.com
  • mongodb.example.com:27018
  • 2001:db8::ff00:42:8329 (IPv6)
  • [2001:db8::ff00:42:8329]:27018 (IPv6 with port requires the IPv6 to be surrounded by square brackets)
  • www.example.com, www2.example.com:123, 192.0.2.1, 192.0.2.2:123, 2001:db8::ff00:42:8329, [2001:db8::ff00:42:8329]:123 (replica set)

    The default value is 127.0.0.1:27017. If left undefined, the default port is 27017.

hibernate.ogm.datastore.port
Deprecated: use hibernate.ogm.datastore.host. The port used by the MongoDB instance. Ignored when multiple hosts are defined. The default value is 27017.
hibernate.ogm.datastore.database
The database to connect to. This property has no default value.
hibernate.ogm.datastore.create_database
If set to true, the database will be created if it doesn’t exist. This property default value is false.
hibernate.ogm.datastore.username
The username used when connecting to the MongoDB server. This property has no default value.
hibernate.ogm.datastore.password
The password used to connect to the MongoDB server. This property has no default value. This property is ignored if the username isn’t specified.
hibernate.ogm.error_handler
The fully-qualified class name, class object or an instance of ErrorHandler to get notified upon errors during flushes (see Section 6.3.1, “Acting upon errors during application of changes”)
hibernate.ogm.mongodb.driver.*
Defines a prefix for all options which should be passed through to the MongoDB driver. For available options refer to the JavaDocs of MongoClientOptions.Builder. All String, int and boolean properties can be set, eg hibernate.ogm.mongodb.driver.serverSelectionTimeout.
hibernate.ogm.mongodb.authentication_mechanism

Define the authentication mechanism to use. Possible values are:

  • BEST: Handshakes with the server to find the best authentication mechanism.
  • SCRAM_SHA_1: The SCRAM SHA 1 Challenge Response mechanism as described in this RFC.
  • MONGODB_CR: The MongoDB Challenge Response mechanism (deprecated since MongoDB 3)
  • GSSAPI: The GSSAPI mechanism. See the RFC
  • MONGODB_X509: The MongoDB X.509
  • PLAIN: The PLAIN mechanism. See the RFC
hibernate.ogm.datastore.document.association_storage

Defines the way OGM stores association information in MongoDB. The following two strategies exist (values of the org.hibernate.ogm.datastore.document.options.AssociationStorageType enum):

  • IN_ENTITY: store association information within the entity
  • ASSOCIATION_DOCUMENT: store association information in a dedicated document per association

IN_ENTITY is the default and recommended option unless the association navigation data is much bigger than the core of the document and leads to performance degradation.

hibernate.ogm.mongodb.association_document_storage

Defines how to store assocation documents (applies only if the ASSOCIATION_DOCUMENT association storage strategy is used). Possible strategies are (values of the org.hibernate.ogm.datastore.mongodb.options.AssociationDocumentStorageType enum):

  • GLOBAL_COLLECTION (default): stores the association information in a unique MongoDB collection for all associations
  • COLLECTION_PER_ASSOCIATION stores the association in a dedicated MongoDB collection per association
hibernate.ogm.datastore.document.map_storage

Defines the way OGM stores the contents of map-typed associations in MongoDB. The following two strategies exist (values of the org.hibernate.ogm.datastore.document.options.MapStorageType enum):

  • BY_KEY: map-typed associations with a single key column which is of type String will be stored as a sub-document, organized by the given key; Not applicable for other types of key columns, in which case always AS_LIST will be used
  • AS_LIST: map-typed associations will be stored as an array containing a sub-document for each map entry. All key and value columns will be contained within the array elements
hibernate.ogm.mongodb.write_concern

Defines the write concern setting to be applied when issuing writes against the MongoDB datastore. Possible settings are (values of the WriteConcernType enum): ACKNOWLEDGED, UNACKNOWLEDGED, FSYNCED, JOURNALED, REPLICA_ACKNOWLEDGED, MAJORITY and CUSTOM. When set to CUSTOM, a custom WriteConcern implementation type has to be specified.

This option is case insensitive and the default value is ACKNOWLEDGED.

hibernate.ogm.mongodb.write_concern_type
Specifies a custom WriteConcern implementation type (fully-qualified name, class object or instance). This is useful in cases where the pre-defined configurations are not sufficient, e.g. if you want to ensure that writes are propagated to a specific number of replicas or given "tag set". Only takes effect if hibernate.ogm.mongodb.write_concern is set to CUSTOM.
hibernate.ogm.mongodb.read_preference
Specifies the ReadPreference to be applied when issuing reads against the MongoDB datastore. Possible settings are (values of the ReadPreferenceType enum): PRIMARY, PRIMARY_PREFERRED, SECONDARY, SECONDARY_PREFERRED and NEAREST. It’s currently not possible to plug in custom read preference types. If you’re interested in such a feature, please let us know.

For more information, please refer to the official documentation.

Note

When bootstrapping a session factory or entity manager factory programmatically, you should use the constants accessible via org.hibernate.ogm.datastore.mongodb.MongoDBProperties when specifying the configuration properties listed above.

Common properties shared between stores are declared on OgmProperties (a super interface of MongoDBProperties).

For maximum portability between stores, use the most generic interface possible.

Fongo is an in-memory java implementation of MongoDB. It intercepts calls to the standard mongo-java-driver for finds, updates, inserts, removes and other methods. The primary use is for lightweight unit testing where you don’t want to spin up a mongod process.

Hibernate OGM provides a FongoDB provider so during tests it can be used instead of MongoDB driver. Note that you don’t need to change your business code to adapt to FongoDB because all adaptations are done under the cover by Hibernate OGM.

To start using FongoDB provider, you should do two things:

The first one is register the provider by using hibernate.ogm.datastore.provider and setting to fongodb.


The second one is adding FongoDB and SLF4J dependencies in your project.

<dependency>
    <groupId>com.github.fakemongo</groupId>
    <artifactId>fongo</artifactId>
    <scope>test</scope>
    <version>2.0.7</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-simple</artifactId>
    <version>1.7.5</version>
    <scope>test</scope>
</dependency>

You can read more about FongoDB project and its limitations at https://github.com/fakemongo/fongo

Hibernate OGM allows to configure store-specific options via Java annotations. You can override global configurations for a specific entity or even a specify property by virtue of the location where you place that annotation.

When working with the MongoDB backend, you can specify the following settings:

Refer to <<mongodb-associations> to learn more about the options related to storing associations.

The following shows an example:


The @WriteConcern annotation on the entity level expresses that all writes should be done using the JOURNALED setting. Similarly, the @ReadPreference annotation advices the engine to preferably read that entity from the primary node if possible. The other two annotations on the type-level specify that all associations of the Zoo class should be stored in separate assocation documents, using a dedicated collection per association. This setting applies to the animals and employees associations. Only the elements of the visitors association will be stored in the document of the corresponding Zoo entity as per the configuration of that specific property which takes precedence over the entity-level configuration.

In addition to the annotation mechanism, Hibernate OGM also provides a programmatic API for applying store-specific configuration options. This can be useful if you can’t modify certain entity types or don’t want to add store-specific configuration annotations to them. The API allows set options in a type-safe fashion on the global, entity and property levels.

When working with MongoDB, you can currently configure the following options using the API:

To set these options via the API, you need to create an OptionConfigurator implementation as shown in the following example:


The call to configureOptionsFor(), passing the store-specific identifier type MongoDB, provides the entry point into the API. Following the fluent API pattern, you then can configure global options (writeConcern(), readPreference()) and navigate to single entities or properties to apply options specific to these (associationStorage() etc.). The call to writeConcern() for the Animal entity shows how a specific write concern type can be used. Here RequiringReplicaCountOf is a custom implementation of WriteConcern which ensures that writes are propagated to a given number of replicas before a write is acknowledged.

Options given on the property level precede entity-level options. So e.g. the animals association of the Zoo class would be stored using the in entity strategy, while all other associations of the Zoo entity would be stored using separate association documents.

Similarly, entity-level options take precedence over options given on the global level. Global-level options specified via the API complement the settings given via configuration properties. In case a setting is given via a configuration property and the API at the same time, the latter takes precedence.

Note that for a given level (property, entity, global), an option set via annotations is overridden by the same option set programmatically. This allows you to change settings in a more flexible way if required.

To register an option configurator, specify its class name using the hibernate.ogm.option.configurator property. When bootstrapping a session factory or entity manager factory programmatically, you also can pass in an OptionConfigurator instance or the class object representing the configurator type.

Hibernate OGM tries to make the mapping to the underlying datastore as natural as possible so that third party applications not using Hibernate OGM can still read and update the same datastore. We worked particularly hard on the MongoDB model to offer various classic mappings between your object model and the MongoDB documents.

To describe things simply, each entity is stored as a MongoDB document. This document is stored in a MongoDB collection named after the entity type. The navigational information for each association from one entity to (a set of) entity is stored in the document representing the entity we are departing from.

Each entity is represented by a document. Each property or more precisely column is represented by a field in this document, the field name being the column name.

Hibernate OGM supports by default the following property types:

  { "text" : "Hello world!" }
  { "delimiter" : "/" }
  { "favorite" : true } # default mapping
  { "favorite" : "T" } # if @Type(type = "true_false") is given
  { "favorite" : "Y" } # if @Type(type = "yes_no") is given
  { "favorite" : 1 } # if @Type(type = "numeric_boolean") is given
  { "display_mask" : "70" }
  { "pdfAsBytes" : BinData(0,"MTIzNDU=") }
  { "urlPort" : 80 }
  { "stockCount" : 12309 }
  { "userId" : NumberLong("-6718902786625749549") }
  { "visitRatio" : 10.39 }
  { "tax_percentage" : 12.34 }
  { "site_weight" : "21.77" }
  { "site_weight" : "444" }
  { "creation" : "2014/11/03 16:19:49:283 +0000" }
  { "last_update" : ISODate("2014-11-03T16:19:49.283Z") }
  { "serialNumber" : "71f5713d-69c4-4b62-ad15-aed8ce8d10e0" }
  { "url" : "http://www.hibernate.org/" }
  { "object_id" : ObjectId("547d9b40e62048750f25ef77") }

Entities are stored as MongoDB documents and not as BLOBs: each entity property will be translated into a document field. You can use @Table and @Column annotations to rename respectively the collection the document is stored in and the document’s field a property is persisted in.



An identifier type may be one of the built-in types or a more complex type represented by an embedded class. When you use a built-in type, the identifier is mapped like a regular property. When you use an embedded class, then the _id is representing a nested document containing the embedded class properties.



Generally, it is recommended though to work with MongoDB’s object id data type. This will facilitate the integration with other applications expecting that common MongoDB id type. To do so, you have two options:

  • Define your id property as org.bson.types.ObjectId
  • Define your id property as String and annotate it with @Type(type="objectid")

In both cases the id will be stored as native ObjectId in the datastore.



You can assign id values yourself or let Hibernate OGM generate the value using the @GeneratedValue annotation.

There are 4 different strategies:

1) IDENTITY generation strategy

The preferable strategy, Hibernate OGM will create the identifier upon insertion. To apply this strategy the id must be one of the following:

like in the following examples:



2) TABLE generation strategy



3) SEQUENCE generation strategy



4) AUTO generation strategy

If the property hibernate.id.new_generator_mappings is set to false, AUTO will behave as the IDENTITY strategy.

If the property hibernate.id.new_generator_mappings is set to true, AUTO will behave as the SEQUENCE strategy.




Hibernate OGM stores elements annotated with @Embedded or @ElementCollection as nested documents of the owning entity.




The class GrandChild has only one attribute name, this means that Hibernate OGM doesn’t need to store the name of the attribute.

If the nested document has two or more fields, like in the following example, Hibernate OGM will store the name of the fields as well.


Note

You can override the column name used for a property of an embedded object. But you need to know that the default column name is the concatenation of the embedding property, a . (dot) and the embedded property (recursively for several levels of embedded objects).

The MongoDB datastore treats dots specifically as it transforms them into nested documents. If you want to override one column name and still keep the nested structure, don’t forget the dots.

That’s a bit abstract, so let’s use an example.

@Entity
class Order {
    @Id String number;
    User user;
    Address shipping;
    @AttributeOverrides({
        @AttributeOverride(name="name", column=@Column(name="delivery.provider"),
        @AttributeOverride(name="expectedDelaysInDays", column=@Column(name="delivery.delays")
    })
    DeliveryProvider deliveryProvider;
    CreditCardType cardType;
}

// default columns
@Embedded
class User {
    String firstname;
    String lastname;
}

// override one column
@Embeddable
public Address {
    String street;
    @Column(name="shipping.dest_city")
    String city;
}

// both columns overridden from the embedding side
@Embeddable
public DeliveryProvider {
    String name;
    Integer expectedDelaysInDays;
}

// do not use dots in the overriding
// and mix levels (bad form)
@Embedded
class CreditCardType {
    String merchant;
    @Column(name="network")
    String network;
}
{
    "_id": "123RF33",
    "user": {
        "firstname": "Emmanuel",
        "lastname": "Bernard"
    },
    "shipping": {
        "street": "1 av des Champs Elysées",
        "dest_city": "Paris"
    },
    "delivery": {
        "provider": "Santa Claus Inc.",
        "delays": "1"
    }
    "network": "VISA",
    "cardType: {
        "merchant": "Amazon"
    }
}

If you share the same embeddable in different places, you can use JPA’s @AttributeOverride to override columns from the embedding side. This is the case of DeliveryProvider in our example.

If you omit the dot in one of the columns, this column will not be part of the nested document. This is demonstrated by the CreditCardType. We advise you against it. Like crossing streams, it is bad form. This approach might not be supported in the future.

Hibernate OGM MongoDB proposes three strategies to store navigation information for associations. The three possible strategies are:

To switch between these strategies, use of the three approaches to options:

In this strategy, Hibernate OGM stores the id(s) of the associated entity(ies) into the entity document itself. This field stores the id value for to-one associations and an array of id values for to-many associations. An embedded id will be represented by a nested document. For indexed collections (i.e. List or Map), the index will be stored along the id.

Note

When using this strategy the annotations @JoinTable will be ignored because no collection is created for associations.

You can use @JoinColumn to change the name of the field that stores the foreign key (as an example, see Example 11.24, “Unidirectional one-to-one with @JoinColumn”).



In a true one-to-one association, it is possible to share the same id between the two entities and therefore a foreign key is not required. You can see how to map this type of association in the following example:






Here we see that the embedded id is represented as a nested document and directly referenced by the associations.



A map can be used to represent an association, in this case Hibernate OGM will store the key of the map and the associated id.


If the map value cannot be represented by a single field (e.g. when referencing a type with a composite id or using an embeddable type as map value type), a sub-document containing all the required fields will be stored as value.

If the map key either is not of type String or it is made up of several columns (composite map key), the optimized structure shown in the example above cannot be used as MongoDB only allows for Strings as field names. In that case the association will be represented by a list of sub-documents, also containing the map key column(s). You can use @MapKeyColumn to rename the field containing the key of the map, otherwise it will default to "<%COLLECTION_ROLE%>_KEY", e.g. "addresses_KEY".


In case you want to enforce the list-style represention also for maps with a single key column of type String (e.g. when reading back data persisted by earlier versions of Hibernate OGM), you can do so by setting the option hibernate.ogm.datastore.document.map_storage to the value AS_LIST.




In this strategy, Hibernate OGM creates a MongoDB collection per association in which it will store all navigation information for that particular association.

This is the strategy closest to the relational model. If an entity A is related to B and C, 2 collections will be created. The name of this collection is made of the association table concatenated with associations_.

For example, if the BankAccount and Owner are related, the collection used to store will be named associations_Owner_BankAccount. You can rename The prefix is useful to quickly identify the association collections from the entity collections. You can also decide to rename the collection representing the association using @JoinTable (see an example)

Each document of an association collection has the following structure:

  • _id contains the id of the owner of relationship
  • rows contains all the id of the related entities

Note

The preferred approach is to use the in-entity strategy but this approach can alleviate the problem of having documents that are too big.



Note

This strategy won’t affect *-to-one associations or embedded collections.


The order of the element in the list might be preserved using @OrderColumn. Hibernate OGM will store the order adding an additional fieldd to the document containing the association.




You can change the name of the collection containing the association using the @JoinTable annotation. In the following example, the name of the collection containing the association is OwnerBankAccounts (instead of the default associations_AccountOwner_BankAccount)


With this strategy, Hibernate OGM creates a single collection named Associations in which it will store all navigation information for all associations. Each document of this collection is structured in 2 parts. The first is the _id field which contains the identifier information of the association owner and the name of the association table. The second part is the rows field which stores (into an embedded collection) all ids that the current instance is related to.


For a bidirectional relationship, another document is created where ids are reversed. Don’t worry, Hibernate OGM takes care of keeping them in sync:






You can express queries in a few different ways:

While you can use JP-QL for simple queries, you might hit limitations. The current recommended approach is to use native MongoQL if your query involves nested (list of) elements.

Hibernate OGM also supports certain forms of native queries for MongoDB. Currently two forms of native queries are available via the MongoDB backend:

The former always maps results to entity types. The latter either maps results to entity types or to certain supported forms of projection. Note that parameterized queries are not supported by MongoDB, so don’t expect Query#setParameter() to work.

You can execute native queries as shown in the following example:


The result of a query is a managed entity (or a list thereof) or a projection of attributes in form of an object array, just like you would get from a JP-QL query.


Native queries can also be created using the @NamedNativeQuery annotation:


Hibernate OGM stores data in a natural way so you can still execute queries using the MongoDB driver, the main drawback is that the results are going to be raw MongoDB documents and not managed entities.

Hibernate OGM can execute native queries expressed using the MongoDB CLI syntax with some limitations. Currently find(), findOne(), findAndModify(), and count() queries are supported. Furthermore, three types of write queries are supported via the CLI syntax: insert(), remove(), and update(). Other query types may be supported in future versions.

As one would expect, find(), findOne(), findAndModify(), and count() can be executed using javax.persistence.Query.getSingleResult() or javax.persistence.Query.getResultList(), while insert(), remove(), and update() require using javax.persistence.Query.executeUpdate(). Also note that, javax.persistence.Query.executeUpdate() may return -1 in case execution of a query was not acknowledged relative to the write concern used.

The following functions can be used in the provided JSON: BinData, Date, HexData, ISODate, NumberLong, ObjectId, Timestamp, RegExp, DBPointer, UUID, GUID, CSUUID, CSGUID, JUUID, JGUID, PYUUID, PYGUID.

No cursor operations such as sort() are supported. Instead use the corresponding MongoDB query modifiers such as $orderby within the criteria parameter.

You can limit the results of a query using the setMaxResults(…​) method.

JSON parameters passed via the CLI syntax must be specified using the strict mode. Specifically, keys need to be given within quotes; the only relaxation of this is that single quotes may be used when specifying attribute names/values to facilitate embedding queries within Java strings.

Note that results of projections are returned as retrieved from the MongoDB driver at the moment and are not (yet) converted using suitable Hibernate OGM type implementations. This requirement is tracked under OGM-1031.




Warning

Support for the $regexp operator is limited to the string syntax. We do not support the /pattern/ syntax as it is not currently supported by the MongoDB Java driver.

Neo4j is a robust (fully ACID) transactional property graph database. This kind of databases are suited for those type of problems that can be represented with a graph like social relationships or road maps for example.

At the moment only the support for the embedded Neo4j is included in OGM.

Hibernate OGM tries to make the mapping to the underlying datastore as natural as possible so that third party applications not using Hibernate OGM can still read and update the same datastore.

To make things simple, each entity is represented by a node, each embedded object is also represented by a node. Links between entities (whether to-one to to-many associations) are represented by relationships between nodes. Entity and embedded nodes are labelled ENTITY and EMBEDDED respectively.

Entities are stored as Neo4j nodes, which means each entity property will be translated into a property of the node. The name of the table mapping the entity is used as label.

You can use the name property of the @Table and @Column annotations to rename the label and the node’s properties.

An additional label ENTITY is added to the node.



An association, bidirectional or unidirectional, is always mapped using one relationship, beginning at the owning side of the association. This is possible because in Neo4j relationships can be navigated in both directions.

The type of the relationships depends on the type of the association, but in general it is the role of the association on the main side. The only property stored on the relationship is going to be the index of the association when required, for example when the association is annotated with @OrderColumn or when a java.util.Map is used.

In Neo4j nodes are connected via relationship, this means that we don’t need to create properties which store foreign column keys. This means that annotation like @JoinColumn won’t have any effect.










Hibernate OGM supports the table generation strategy as well as the sequence generation strategy with Neo4j. It is generally recommended to work with the latter, as it allows a slightly more efficient querying for the next sequence value.

Sequence-based generators are represented by nodes in the following form:


Each sequence generator node is labelled with SEQUENCE. The sequence name can be specified via @SequenceGenerator#sequenceName(). A unique constraint is applied to the property sequence_name in order to ensure uniqueness of sequences.

If required, you can set the initial value of a sequence and the increment size via @SequenceGenerator#initialValue() and @SequenceGenerator#allocationSize(), respectively. The options @SequenceGenerator#catalog() and @SequenceGenerator#schema() are not supported.

Table-based generators are represented by nodes in the following form:


Each table generator node is labelled with TABLE_BASED_SEQUENCE and the table name as specified via @TableGenerator#table(). The sequence name is to be given via @TableGenerator#pkColumnValue(). The node properties holding the sequence name and value can be configured via @TableGenerator#pkColumnName() and @TableGenerator#valueColumnName(), respectively. A unique constraint is applied to the property sequence_name to avoid the same sequence name is used twice within the same "table".

If required, you can set the initial value of a sequence and the increment size via @TableGenerator#initialValue() and @TableGenerator#allocationSize(), respectively. The options @TableGenerator#catalog(), @TableGenerator#schema(), @TableGenerator#uniqueConstraints() and @TableGenerator#indexes() are not supported.

You can express queries in a few different ways:

While you can use JP-QL for simple queries, you might hit limitations. The current recommended approach is to use native Cypher queries if your query involves nested (list of) elements.

Hibernate OGM also supports Cypher queries for Neo4j. You can execute Cypher queries as shown in the following example:


The result of a query is a managed entity (or a list thereof) or a projection of attributes in form of an object array, just like you would get from a JP-QL query.


Native queries can also be created using the @NamedNativeQuery annotation:


Hibernate OGM stores data in a natural way so you can still execute queries using your favorite tool, the main drawback is that the results are going to be raw Neo4j elements and not managed entities.

CouchDB is a document-oriented datastore which stores your data in form of JSON documents and exposes its API via HTTP based on REST principles. It is thus very easy to access from a wide range of languages and applications.

Note

Support for CouchDB is considered an EXPERIMENTAL feature as of this release. In particular you should be prepared for possible changes to the persistent representation of mapped objects in future releases.

Also be aware that partial updates are unsupported at the moment (OGM-388). The entire document will be replaced during any updates. This means that fields possibly written by other applications but not mapped to properties in your domain model will get lost.

The ASSOCIATION_DOCUMENT mode for storing associations should be used with care as there is potential for lost updates (OGM-461). It is recommended to use the IN_ENTITY mode (which is the default).

Should you find any bugs or have feature requests for this dialect, then please open a ticket in the OGM issue tracker.

Hibernate OGM uses the excellent RESTEasy library to talk to CouchDB stores, so there is no need to include any of the Java client libraries for CouchDB in your classpath.

The following properties are available to configure CouchDB support in Hibernate OGM:

CouchDB datastore configuration properties

hibernate.ogm.datastore.provider
To use CouchDB as a datastore provider, this property must be set to couchdb_experimental
hibernate.ogm.option.configurator
The fully-qualified class name or an instance of a programmatic option configurator (see Section 13.1.2, “Programmatic configuration”)
hibernate.ogm.datastore.host

The hostname and port of the CouchDB instance. The optional port is concatenated to the host and separated by a colon. Let’s see a few valid examples:

  • couchdb.example.com
  • couchdb.example.com:5985
  • 2001:db8::ff00:42:8329 (IPv6)
  • [2001:db8::ff00:42:8329]:5985 (IPv6 with port requires the IPv6 to be surrounded by square brackets)

    Listing multiple initial hosts for fault tolerance is not supported. The default value is 127.0.0.1:5984. If left undefined, the default port is 5984.

hibernate.ogm.datastore.port
Deprecated: use hibernate.ogm.datastore.host. The port used by the CouchDB instance. The default value is 5984.
hibernate.ogm.datastore.database
The database to connect to. This property has no default value.
hibernate.ogm.datastore.create_database
Whether to create the specified database in case it does not exist or not. Can be true or false (default). Note that the specified user must have the right to create databases if set to true.
hibernate.ogm.datastore.username
The username used when connecting to the CouchDB server. Note that this user must have the right to create design documents in the chosen database. This property has no default value. Hibernate OGM currently does not support accessing CouchDB via HTTPS; if you’re interested in such functionality, let us know.
hibernate.ogm.datastore.password
The password used to connect to the CouchDB server. This property has no default value. This property is ignored if the username isn’t specified.
hibernate.ogm.error_handler
The fully-qualified class name, class object or an instance of ErrorHandler to get notified upon errors during flushes (see Section 6.3.1, “Acting upon errors during application of changes”)
hibernate.ogm.datastore.document.association_storage
Defines the way OGM stores association information in CouchDB.

The following two strategies exist (values of the org.hibernate.ogm.datastore.document.options.AssociationStorageType enum): IN_ENTITY (store association information within the entity) and ASSOCIATION_DOCUMENT (store association information in a dedicated document per association).

IN_ENTITY is the default and recommended option unless the association navigation data is much bigger than the core of the document and leads to performance degradation.

hibernate.ogm.datastore.document.map_storage

Defines the way OGM stores the contents of map-typed associations in CouchDB. The following two strategies exist (values of the org.hibernate.ogm.datastore.document.options.MapStorageType enum):

  • BY_KEY: map-typed associations with a single key column which is of type String will be stored as a sub-document, organized by the given key; Not applicable for other types of key columns, in which case always AS_LIST will be used
  • AS_LIST: map-typed associations will be stored as an array containing a sub-document for each map entry. All key and value columns will be contained within the array elements

Note

When bootstrapping a session factory or entity manager factory programmatically, you should use the constants accessible via CouchDBProperties when specifying the configuration properties listed above. Common properties shared between (document) stores are declared on OgmProperties and DocumentStoreProperties, respectively. To ease migration between stores, it is recommended to reference these constants directly from there.

In addition to the annotation mechanism, Hibernate OGM also provides a programmatic API for applying store-specific configuration options. This can be useful if you can’t modify certain entity types or don’t want to add store-specific configuration annotations to them. The API allows set options in a type-safe fashion on the global, entity and property levels.

When working with CouchDB, you can currently configure the following options using the API:

To set this option via the API, you need to create an OptionConfigurator implementation as shown in the following example:


The call to configureOptionsFor(), passing the store-specific identifier type CouchDB, provides the entry point into the API. Following the fluent API pattern, you then can configure global options and navigate to single entities or properties to apply options specific to these.

Options given on the property level precede entity-level options. So e.g. the visitors association of the Zoo class would be stored using the in entity strategy, while all other associations of the Zoo entity would be stored using separate association documents.

Similarly, entity-level options take precedence over options given on the global level. Global-level options specified via the API complement the settings given via configuration properties. In case a setting is given via a configuration property and the API at the same time, the latter takes precedence.

Note that for a given level (property, entity, global), an option set via annotations is overridden by the same option set programmatically. This allows you to change settings in a more flexible way if required.

To register an option configurator, specify its class name using the hibernate.ogm.option.configurator property. When bootstrapping a session factory or entity manager factory programmatically, you also can pass in an OptionConfigurator instance or the class object representing the configurator type.

Hibernate OGM tries to make the mapping to the underlying datastore as natural as possible so that third party applications not using Hibernate OGM can still read and update the same datastore. The following describe how entities and associations are mapped to CouchDB documents by Hibernate OGM.

Entities are stored as CouchDB documents and not as BLOBs which means each entity property will be translated into a document field. You can use the name property of the @Table and @Column annotations to rename the collections and the document’s fields if you need to.

CouchDB provides a built-in mechanism for detecting concurrent updates to one and the same document. For that purpose each document has an attribute named _rev (for "revision") which is to be passed back to the store when doing an update. So when writing back a document and the document’s revision has been altered by another writer in parallel, CouchDB will raise an optimistic locking error (you could then e.g. re-read the current document version and try another update).

For this mechanism to work, you need to declare a property for the _rev attribute in all your entity types and mark it with the @Version and @Generated annotations. The first marks it as a property used for optimistic locking, while the latter advices Hibernate OGM to refresh that property after writes since its value is managed by the datastore.

The following shows an example of an entity and its persistent representation in CouchDB.


Note that CouchDB doesn’t have a concept of "tables" or "collections" as e.g. MongoDB does; Instead all documents are stored in one large bucket. Thus Hibernate OGM needs to add two additional attributes: $type which contains the type of a document (entity vs. association documents) and $table which specifies the entity name as derived from the type or given via the @Table annotation.

Note

Attributes whose name starts with the "$" character are managed by Hibernate OGM and thus should not be modified manually. Also it is not recommended to start the names of your attributes with the "$" character to avoid collisions with attributes possibly introduced by Hibernate OGM in future releases.


You can assign id values yourself or let Hibernate OGM generate the value using the @GeneratedValue annotation.

Two main strategies are supported:

Both strategy will create a new document containg the next value to use for the id, the difference between the two strategies is the name of the field containing the values.

Hibernate OGM goes not support the IDENTITY strategy and an exception is thrown at startup when it is used. The AUTO strategy is the same as the SEQUENCE one.

1) TABLE generation strategy



2) SEQUENCE generation strategy



Hibernate OGM stores elements annotated with @Embedded or @ElementCollection as nested documents of the owning entity.




The class GrandChild has only one attribute name, this means that Hibernate OGM doesn’t need to store the name of the attribute.

If the nested document has two or more fields, like in the following example, Hibernate OGM will store the name of the fields as well.


Hibernate OGM CouchDB provides two strategies to store navigation information for associations:

You can switch between the two strategies using:

With this strategy, Hibernate OGM directly stores the id(s) of the other side of the association into a field or an embedded document depending if the mapping concerns a single object or a collection. The field that stores the relationship information is named like the entity property.





In a true one-to-one association, it is possible to share the same id between the two entities and therefore a foreign key is not required. You can see how to map this type of association in the following example:





A map can be used to represents an association, in this case Hibernate OGM will store the key of the map and the associated id.


If the map value cannot be represented by a single field (e.g. when referencing a type with a composite id or using an embeddable type as map value type), a sub-document containing all the required fields will be stored as value.

If the map key either is not of type String or it is made up of several columns (composite map key), the optimized structure shown in the example above cannot be used. In that case the association will be represented by a list of sub-documents, also containing the map key column(s). You can use @MapKeyColumn to rename the field containing the key of the map, otherwise it will default to "<%COLLECTION_ROLE%>_KEY", e.g. "addresses_KEY".

In case you want to enforce the list-style represention also for maps with a single key column of type String you can use the option hibernate.ogm.datastore.document.map_storage to do so.






With this strategy, Hibernate OGM uses separate association documents (with $type set to "association") to store all navigation information. Each assocation document is structured in 2 parts. The first is the _id field which contains the identifier information of the association owner and the name of the association table. The second part is the rows field which stores (into an embedded collection) all ids that the current instance is related to.


For a bidirectional relationship, another document is created where ids are reversed. Don’t worry, Hibernate OGM takes care of keeping them in sync:


Note

This strategy won’t affect *-to-one associations or embedded collections.


Using the annotation @JoinTable it is possible to change the value of the document containing the association.




Cassandra is a distributed column family database.

This implementation uses CQL3 over the native wire protocol with java-driver. The currently supported version is Cassandra 2.1.

Note

Support for Cassandra is considered an EXPERIMENTAL feature of this release.

Should you find any bugs or have feature requests for this dialect, then please open a ticket in the OGM issue tracker.

Configuring Hibernate OGM to use Cassandra is easy:

Each Entity type maps to one Cassandra table. Each Entity instance maps to one CQL3 row of the table, each property of the Entity being one CQL3 column.

CQL3 table and column names are always quoted to preserve case consistency with the Java layer, with the table name matching the Entity class and the column names matching the Entity’s properties. The @Table and @Column annotations can be used to override identifier names in the usual manner.

Embedded objects are stored as additional columns in the owning Entitie’s table. The columns are named as EmbeddedTypeName.FieldOfEmbeddedType The type and field names can be overridden by annotations, but concatenation token delimiter cannot.

CQL3 types

CQL3 supports a smaller selection of numeric data types than Hibernate, so the missing types are automatically converted. byte and short values are promoted to integer. java.math.BigDecimal is converted to decimal.

CQL3 has no character type, so character is promoted to varchar i.e. String. Strings are UTF-8, not ascii.

CQL3 does not distinguish between byte[] and BLOB types for binary storage. These are handled equivalently.

CQL3 does not have a Calendar type, so these are converted to Dates, which are stores as time offset from the unix epoch.

Redis is a key-value datastore which stores your data in a variety of data structures. Although there is no one-and-only style how to map data between data structures and Redis, two major styles are are most common:

  • Storing entities using keys as JSON documents
  • Storing entities using hashes as key-value pairs

Note

Support for Redis is considered an EXPERIMENTAL feature as of this release. In particular you should be prepared for possible changes to the persistent representation of mapped objects in future releases.

Also be aware of the fact that partial updates using the JSON dialect are unsupported at the moment Instead always the entire document will be replaced during updates. This means that fields possibly written by other applications but not mapped to properties in your domain model will get lost.

The JSON dialect supports two modes for storing associations: The ASSOCIATION_DOCUMENT mode should be used with care as there is potential for lost updates (OGM-461). It is recommended to use the IN_ENTITY mode (which is the default).

Should you find any bugs or have feature requests for this dialect, then please open a ticket in the OGM issue tracker.

Hibernate OGM uses the lettuce library to talk to Redis, so you need the client libraries to use Hibernate OGM Redis.

The following properties are available to configure Redis support in Hibernate OGM:

Redis datastore configuration properties

hibernate.ogm.datastore.provider
To use Redis as a datastore provider, this property must be set to redis_experimental
hibernate.ogm.datastore.grid_dialect
The dialect type how Hibernate OGM Redis maps entities and associations within Redis. The following two dialects exist: org.hibernate.ogm.datastore.redis.RedisJsonDialect (store entities as JSON documents within Redis keys. Associations are mapped to Redis lists/sets) and org.hibernate.ogm.datastore.redis.RedisHashDialect (store entities as key-value pairs within Redis hashes. Associations are mapped as JSON documents to Redis lists/sets)
hibernate.ogm.datastore.host

The hostname and port of the Redis instance. The optional port is concatenated to the host and separated by a colon. Let’s see a few valid examples:

  • redis.example.com
  • redis.example.com:6379

    Listing multiple initial hosts for fault tolerance is not supported. The default value is 127.0.0.1:6379. If left undefined, the default port is 6379.

hibernate.ogm.datastore.database
The database number to connect to. If left undefined, the default number is 0. Note that Redis databases are identified with a number from 0 to 16.
hibernate.ogm.datastore.password
The password used to connect to the Redis server. This property has no default value.
hibernate.ogm.redis.ssl
Boolean flag to enable SSL connections to Redis. Note that Redis does not support native SSL and SSL is provided by tools like stunnel
hibernate.ogm.redis.connection_timeout
Defines the timeout used by the driver when the connection to the Redis instance is initiated. This configuration is expressed in milliseconds. The default value is 5000.
hibernate.ogm.redis.cluster
Boolean flag to enable Redis Cluster mode. It’s strongly recommended to use simple primary and association keys as composite keys are serialized as JSON which may interfere the slot distribution. Curly braces within keys are used to denote hash tags to group keys within one slot.
hibernate.ogm.redis.ttl
Defines the TTL for entities and associations. TTL can be configured on entity and association level (see Section 15.1.1, “Annotation based configuration” This property has no default value.
hibernate.ogm.error_handler
The fully-qualified class name, class object or an instance of ErrorHandler to get notified upon errors during flushes (see Section 6.3.1, “Acting upon errors during application of changes”)
hibernate.ogm.datastore.redis.association_storage
Defines the way OGM stores association information in Redis. The following two strategies exist for the JSON dialect (values of the org.hibernate.ogm.datastore.document.options.AssociationStorageType enum): IN_ENTITY (store association information within the entity) and ASSOCIATION_DOCUMENT (store association information in a dedicated document per association). IN_ENTITY is the default and recommended option unless the association navigation data is much bigger than the core of the document and leads to performance degradation. The Redis hash dialect supports only the ASSOCIATION_DOCUMENT strategy.
hibernate.ogm.datastore.document.map_storage

Defines the way OGM stores the contents of map-typed associations in Redis. The following two strategies exist (values of the org.hibernate.ogm.datastore.document.options.MapStorageType enum):

  • BY_KEY: map-typed associations with a single key column which is of type String will be stored as a sub-document, organized by the given key; Not applicable for other types of key columns, in which case always AS_LIST will be used
  • AS_LIST: map-typed associations will be stored as an array containing a sub-document for each map entry. All key and value columns will be contained within the array elements The default value is BY_KEY.

Note

When bootstrapping a session factory or entity manager factory programmatically, you should use the constants accessible via RedisProperties when specifying the configuration properties listed above. Common properties shared between stores are declared on OgmProperties. To ease migration between stores, it is recommended to reference these constants directly from there.

Hibernate OGM allows to configure store-specific options via Java annotations. When working with the Redis backend, you can specify how associations should be stored using the AssociationStorage annotation. A strategy for storing the contents of map-typed associations can be defined using the @MapStorage annotation.

(refer to Section 15.2, “Storage principles” to learn more about association storage strategies in general).

The following shows an example:



Redis supports a native TTL/expiry mechanism. Keys can expire at a date or after a certain period. Hibernate OGM allows to specify a TTL value on entities and associations. The TTL is set after persisting the entity using the PEXPIRE command. Every write to Redis will set a new TTL.

The annotation on the entity level expresses that all associations of the Zoo class should be stored in separate assocation documents. This setting applies to the animals and employees associations. Only the elements of the visitors association will be stored in the document of the corresponding Zoo entity as per the configuration of that specific property which takes precedence over the entity-level configuration.

Hibernate OGM tries to make the mapping to the underlying datastore as natural as possible so that third party applications not using Hibernate OGM can still read and update the same datastore. Hibernate OGM facilitates two styles of data mapping within Redis:

The following describe how entities and associations are mapped to Redis data structures by Hibernate OGM.

The JSON mapping dialect maps entities to JSON documents and stores the JSON data within Redis keys. A document is self-contained and does not support partial updates.

Hibernate OGM stores elements annotated with @Embedded or @ElementCollection as nested documents of the owning entity.




The class GrandChild has only one attribute name, this means that Hibernate OGM doesn’t need to store the name of the attribute.

If the nested document has two or more fields, like in the following example, Hibernate OGM will store the name of the fields as well.


The Redis Hash mapping dialect maps entities to key-value pairs. It stores the data within Redis hashes. Hashes support partial updates. While the JSON dialect discards not mapped fields in the entity model the hash dialect does not touch fields that are not mapped to the entity model.

Entities are stored as key-value pairs within Redis hashes. Each entity property will be translated into a hash field and is represented as java.lang.String. The Redis hash dialect supports only flat data structures hence nested entities and associations are represented as JSON documents within the association documents in Redis lists/sets. You can use the name property of the @Table and @Column annotations to rename the collections and the document’s fields if you need to.

Redis has no built-in mechanism for detecting concurrent updates to one and the same document.

The following shows an example of an entity and its persistent representation in Redis.


Redis doesn’t have a concept of "tables"; Instead all values are stored in a hash as key values. The hash key contains the table name and the primary key of the entity. Thus Hibernate OGM needs to add two additional attributes:


Hibernate OGM stores elements annotated with @Embedded or @ElementCollection as nested documents of the owning entity.




The class GrandChild has only one attribute name, this means that Hibernate OGM doesn’t need to store the name of the attribute.

If the nested document has two or more fields, like in the following example, Hibernate OGM will store the name of the fields as well.


Hibernate OGM Redis provides two strategies to store navigation information for associations:

You can switch between the two strategies using:

With this strategy, Hibernate OGM directly stores the id(s) of the other side of the association into a field or an embedded document depending if the mapping concerns a single object or a collection. The field that stores the relationship information is named like the entity property.





In a true one-to-one association, it is possible to share the same id between the two entities and therefore a foreign key is not required. You can see how to map this type of association in the following example:





A map can be used to represents an association, in this case Hibernate OGM will store the key of the map and the associated id.


If the map value cannot be represented by a single field (e.g. when referencing a type with a composite id or using an embeddable type as map value type), a sub-document containing all the required fields will be stored as value.

If the map key either is not of type String or it is made up of several columns (composite map key), the optimized structure shown in the example above cannot be used. In that case the association will be represented by a list of sub-documents, also containing the map key column(s). You can use @MapKeyColumn to rename the field containing the key of the map, otherwise it will default to "<%COLLECTION_ROLE%>_KEY", e.g. "addresses_KEY".

In case you want to enforce the list-style represention also for maps with a single key column of type String you can use the option hibernate.ogm.datastore.document.map_storage to do so.






With this strategy, Hibernate OGM uses separate association data structures to store all navigation information. The association data structure depends on the type of the association:

Each association has 2 parts. The first is the key. The key consists of a prefix, the identifier information of the association owner, and the name of the association table.

Associations:<%ASSOCIATION_TABLE%:<%ASSOCIATION_ID%:<%COLLECTION_ROLE%, e.g. "Associations:AccountOwner:4f5b48ad-f074-4a64-8cf4-1f9c54a33f76:BankAccount".

The second part is the rows field which stores (into an embedded collection) all ids that the current instance is related to.


For a bidirectional relationship, another list is created where ids are reversed. Don’t worry, Hibernate OGM takes care of keeping them in sync:


Note

This strategy won’t affect *-to-one associations or embedded collections.


Using the annotation @JoinTable it is possible to change the value of the document containing the association.




Redis keys are derived from the Entity name and its Id separated by a colon (:). String-based Id’s are used directly within the key, non-string keys are encoded to JSON. You can use any persistable Java type as identifier type, e.g. String or long. Hibernate OGM will convert the @Id property into a part of the key name so you can name the entity id like you want.

Note that you also can work with embedded ids (via @EmbeddedId), Composite Id’s are mapped to a JSON object containing keys and values. Hibernate OGM thus will create a concatenated representation of the embedded id’s properties in this case. The columns are sorted in alphabetical order to guarantee the same order.


You can assign id values yourself or let Hibernate OGM generate the value using the @GeneratedValue annotation.

Two main strategies are supported:

Both strategies will operate in the keys starting with Identifiers containing the last value of the id. The difference between the two strategies is the name of the key containing the values.

The AUTO strategy is the same as the SEQUENCE one.

The next value is obtained using Redis' HINCRBY command that guarantees to create atomic updates to the underlying data structure.

1) TABLE generation strategy



2) SEQUENCE generation strategy



Note

The value stored in Redis for the sequence is not the one the dialect will return as next number in the sequence. Instead, Hibernate OGM will use it as seed to generate the correct value in the sequence.

Using Hibernate OGM with Redis Cluster is a matter of enabling Redis Cluster mode (see Section 15.1, “Configuring Redis”). Data stored with Hibernate OGM Redis is distributed across Redis Cluster nodes according to the Redis key distribution model based on the hash slot of the key of each entity.