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

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.

2. What we have today

Today, Hibernate OGM does not support all of these goals.
Here is a list of what we have:

store data in key/value stores (Infinispan’s datagrid and Ehcache)

store data in document stores (MongoDB and CouchDB - the latter in preview)

store data in graph databases (Neo4J)

Create, Read, Update and Delete operations (CRUD) for entities

polymorphic entities (support for superclasses, subclasses etc).

embeddable objects (aka components)

support for basic types (numbers, String, URL, Date, enums, etc)

support for associations

support for collections (Set, List, Map, etc)

support for JP-QL queries (not arbitrary joins though)

support for mapping native queries results to managed entities

support for Hibernate Search’s full-text queries

and generally, support for JPA and native Hibernate ORM API support

In short, a perfectly capable Object Mapper for multiple popular NoSQL datastores.

3. Experimental features

As Hibernate OGM is a rather young project, some parts of it may be marked as experimental.
This may affect specific APIs or SPIs (e.g. the case for the SchemaInitializer SPI contract at the moment),
entire dialects (this is the case for the CouchDB dialect at the moment)
or deliverables.

Experimental APIs/SPIs are marked via the @Experimental annotation.
Experimental dialects make that fact apparent through their datastore name (e.g. "COUCHDB_EXPERIMENTAL")
and experimental deliverables use the "experimental" artifact classifier.

If a certain part is marked as experimental it may undergo backwards-incompatible changes in future releases.
E.g. API/SPI methods may be altered, so that code using them needs to be adapted as well.
For experimental dialects the persistent format of data may be changed,
so that a future version of such dialect may not be able to read back data written by previous versions.
A manual update of the affected data may be thus required.
Experimental deliverables should be used with special care, as they are work in progress.
You should use them for testing but not production use cases.

But most of our dialects are mature, so don’t worry ;)

4. Use cases

Here are a few areas where Hibernate OGM can be beneficial:

need to scale your datastore up and down rapidly
(via the underlying NoSQL datastore capability)

Chapter 1. How to get help and contribute on Hibernate OGM

1.1. How to get help

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.

Note

Note that Hibernate OGM uses artifacts from the Maven repository hosted by JBoss.
Make sure to either use the -s settings-example.xml option
or adjust your ~/.m2/settings.xml
according to the descriptions available
on this jboss.org wiki page.

To skip building the documentation, set the skipDocs property to true:

mvn clean install -DskipDocs=true -s settings-example.xml

Tip

If you just want to build the documentation only,
run it from the hibernate-ogm-documentation/manual subdirectory.

1.2.2. How to contribute code effectively

The best way to share code is to fork the Hibernate OGM repository on GitHub,
create a branch and open a pull request when you are ready.
Make sure to rebase your pull request
on the latest version of the master branch before offering it.

Here are a couple of approaches the team follows:

We do small independent commits for each code change.
In particular, we do not mix stylistic code changes (import, typos, etc)
and new features in the same commit.

Commit messages follow this convention:
the JIRA issue number, a short commit summary, an empty line,
a longer description if needed.
Make sure to limit line length to 80 characters, even at this day and age
it makes for more readable commit comments.

OGM-123 Summary of commit operation
Optional details on the commit
and a longer description can be
added here.

A pull request can contain several commits but should be self contained:
include the implementation, its unit tests, its documentation
and javadoc changes if needed.

All commits are proposed via pull requests
and reviewed by another member of the team
before being pushed to the reference repository.
That’s right, we never commit directly upstream without code review.

Chapter 2. Getting started with Hibernate OGM

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:

Java JDK 6 or above

Maven 3.x

Hibernate OGM is published in the JBoss hosted Maven repository.
Adjust your ~/.m2/settings.xml file
according to the guidelines found
on this webpage.
In this example we will use Infinispan as the targeted datastore.

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:

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:

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

<?xml version="1.0"?><persistencexmlns="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-unitname="ogm-jpa-tutorial"transaction-type="JTA"><!-- Use Hibernate OGM provider: configuration will be transparent --><provider>org.hibernate.ogm.jpa.HibernateOgmPersistence</provider><properties><!-- property is optional if you want to use Infinispan, otherwise adjust to your favorite NoSQL Datastore provider. <property name="hibernate.ogm.datastore.provider" value="infinispan"/> --><!-- defines which JTA Transaction we plan to use --><propertyname="hibernate.transaction.jta.platform"value="org.hibernate.service.jta.platform.internal.JBossStandAloneJtaPlatform"/></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 nicelyTransactionManager tm = getTransactionManager();//build the EntityManagerFactory as you would build in in Hibernate ORMEntityManagerFactory emf =Persistence.createEntityManagerFactory("ogm-jpa-tutorial");finalLogger logger =LoggerFactory.getLogger(DogBreedRunner.class);[..]//Persist entities the way you are used to in plain JPAtm.begin();logger.infof("About to store dog and breed");EntityManager em = emf.createEntityManager();Breed collie =newBreed();collie.setName("Collie");em.persist(collie);Dog dina =newDog();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 JPAtm.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();privatestaticfinalString JBOSS_TM_CLASS_NAME ="com.arjuna.ats.jta.TransactionManager";publicstaticTransactionManager getTransactionManager()throwsException{Class<?> tmClass =Main.class.getClassLoader().loadClass(JBOSS_TM_CLASS_NAME);return(TransactionManager) tmClass.getMethod("transactionManager").invoke(null);}

Note

Some JVM do not handle mixed IPv4/IPv6 stacks properly (older
Mac OS X JDK in particular),
if you experience trouble starting the Infinispan cluster,
pass the following property: -Djava.net.preferIPv4Stack=true
to your JVM or upgrade to a recent JDK version.
jdk7u6 (b22) is known to work on Max OS X.

Note

There are some additional constraints related to transactions when working with Neo4j.
You will find more details in the Neo4j transactions section: Section 12.4, “Transactions”

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.

Chapter 3. Architecture

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.

3.1. General architecture

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

Hibernate ORM for JPA support

the NoSQL drivers to interact with the underlying datastore

optionally Hibernate Search for indexing and query purposes

optionally Infinispan’s Lucene Directory to store indexes in Infinispan itself,
or in many other NoSQL using Infinispan’s write-through cachestores

Hibernate OGM itself

Figure 3.1. General architecture

Hibernate OGM reuses as much as possible from the Hibernate ORM infrastructure.
There is no need to rewrite an entirely 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 Map based datastore provider (for testing)

an Infinispan based datastore provider to persist your entities in Infinispan

a 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

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.

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.

3.2. How is data persisted

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:

abstraction between the application object model
and the persistent data model

persist data as basic types

keep the notion of primary key to address an entity

keep the notion of foreign key to link two entities (not enforced)

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

any change in the application object hierarchy / composition
must be reflected in the persistent data

any change in the application object model
will require a migration at the data level

any access to the data by another application
ties both applications losing flexibility

any access to the data from another platform become somewhat more challenging

Why aren’t entities serialized in the key/value entry

There are a couple of reasons why serializing the entity
directly in the datastore - key/value in particular - can lead to problems:

When entities are pointing to other entities are you storing the whole graph?
Hint: this can be quite big!

If doing so, how do you guarantee object identity or even consistency
amongst duplicated objects?
It might make sense to store the same object graph from different root objects.

What happens in case of class schema change?
If you add or remove a property or include a superclass,
you must migrate all entities in your datastore to avoid deserialization issues.

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 table name

the primary key column name(s)

the primary key column value(s)

Figure 3.2. Storing entities

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 tuple as well
or more specifically as a set of 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.

Figure 3.3. Storing associations

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.

Figure 3.4. Storing associations in a document store

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.

3.3. How is data queried

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 that
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 like Voldemort 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:

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

4.1. Bootstrapping Hibernate OGM

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.

4.1.1. Using JPA

The good news is that 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 is no DDL scheme generation options (hbm2ddl)
as NoSQL generally do not require schemas

if you use JTA (which we recommend), you will need to set the JTA platform

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.

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

there is no DDL schema generation options (hbm2ddl)
as Infinispan does not require schemas

you need to set the right transaction strategy
and the right transaction manager lookup strategy
if you use a JTA based transaction strategy
(see Section 4.2, “Environments”)

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.

4.2. Environments

Hibernate OGM runs in various environments,
pretty much what you are used to with Hibernate ORM.
There are however environments where it works better
and has been more thoroughly tested.

4.2.1. In a Java EE container

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

the transaction factory

the JTA platform

a JTA datasource

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.factory_class to either:

org.hibernate.transaction.CMTTransactionFactory
if you use declarative transaction demarcation.

or org.hibernate.transaction.JTATransactionFactory
if you manually demarcate transaction boundaries

Set the JTA platform to the right Java EE container.
The property is hibernate.transaction.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,
use org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform.

In your persistence.xml, you also need to define an existing datasource.
It is not needed by Hibernate OGM
and won’t be used but the JPA specification mandates this setting.

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

4.2.3. Without JTA

While this approach works today, it does not ensure that works are done transactionally
and hence won’t be able to rollback your work.
This will change in the future but in the mean time,
such an environment is not recommended.

Note

For NoSQL datastores not supporting transactions, this is less of a concern.

4.3. Configuration options

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

4.4. Configuring Hibernate Search

Hibernate Search integrates with Hibernate OGM just like it does with Hibernate ORM.
The Hibernate Search version tested is 5.0.0.Final.
Add the dependency to your project - the group id is org.hibernate and artifact id hibernate-search-orm.

Then configure where you want to store your indexes,
map your entities with the relevant index annotations and you are good to go.
For more information, simply check the
Hibernate Search reference documentation.

4.5. How to package Hibernate OGM applications for WildFly 8.2

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

In WildFly 8.2, class loading is based on modules
that have to define explicit dependencies on other modules.
Modules allow to share the same artifacts across multiple applications,
getting you smaller and quicker deployments.

org.hibernate.ogm.<%DATASTORE%>:main, one module for each datastore provider besides Infinispan, with <%DATASTORE%> being one of ehcache, mongodb etc.
You only need to add those modules which you actually intend to use.

Several shared dependencies such as org.hibernate.hql:<%VERSION%> (containing the query parser) and others

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):

Chapter 5. Map your entities

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

5.1. Supported entity mapping

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.

The various inheritance strategies are not supported by Hibernate OGM,
only the table per concrete class strategy is used.
This is not so much a limitation
but rather an acknowledgment of the dynamic nature of NoSQL schemas.
If you feel the need to support other strategies,
let us know (see Section 1.2, “How to contribute”).
Simply do not use @Inheritance nor @DiscriminatorColumn.

5.3. Supported association mapping

All association types are supported (@OneToOne,
@OneToMany, @ManyToOne, @ManyToMany).
Likewise, all collection types are supported (Set, Map,
List).
The way Hibernate OGM stores association information is however quite different
than the traditional RDBMS representation.
Each chapter dedicated to a datastore describes how associations are persisted,
make sure to check them out.

Keep in mind that collections with many entries won’t perform very well
in Hibernate OGM (at least today)
as all of the association navigation for a given entity is stored in a single key.
If your collection is made of 1 million elements,
Hibernate OGM stores 1 million tuples in the association key.

6.3. On flush and transactions

While most underlying 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.

Inside a JTA environment, either the container demarcate the transaction for you
and Hibernate OGM will transparently joins that transaction and flush at commit time.
Or you need to manually demarcate the transaction.
In the latter case,
it is best to start / stop the transaction before retrieving the Session or EntityManager
as show below.
The alternative is to call the EntityManager.joinTransaction() once the transaction has started.

transactionManager.begin();Session session = sessionFactory.openSession();//do your worktransactionManager.commit();// will flush changes to the datastore// or in JPAtransactionManager.begin();EntityManager entityManager = entityManagerFactory.createEntityManager();//do your worktransactionManager.commit();// will flush changes to the datastore

6.4. SPIs

Some of the Hibernate OGM public contracts are geared towards either integrators
or implementors of datastore providers.
They should not be used by a regular application.
These contracts are named SPIs and are in a .spi package.

To keep improving Hibernate OGM, we might break these SPIs between versions.
If you plan on writing a datastore, come and talk to us.

Tip

Non public contracts are stored within a .impl package.
If you see yourself using one of these classes,
beware that we can break these without notice.

Chapter 7. Query your entities

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

7.1. Using JP-QL

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.

Note

For datastores like Infinispan that require Hibernate Search to execute JP-QL queries,
the following preconditions must be met:

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:

Example 7.1. Some JP-QL queries

// query returning an entity based on a simple predicate
select h from Hypothesis h where id = 16
// projection of the entity property
select id, description from Hypothesis h where id = 16
// projection of the embedded properties
select h.author.address.street from Hypothesis h where h.id = 16
// predicate comparing a property value and a literal
from Hypothesis h where h.position = '2'
// negation
from Hypothesis h where not h.id = '13'
from Hypothesis h where h.position <> 4
// conjunction
from Hypothesis h where h.position = 2 and not h.id = '13'
// named parameters
from Hypothesis h where h.description = :myParam
// range query
from Hypothesis h where h.description BETWEEN :start and :end"
// comparisons
from Hypothesis h where h.position < 3
// in
from Hypothesis h where h.position IN (2, 3, 4)
// like
from Hypothesis h where h.description LIKE '%dimensions%'
// comparison with null
from Hypothesis h where h.description IS null
// order by
from Hypothesis h where h.description IS NOT null ORDER BY id
from Helicopter h order by h.make desc, h.name

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.

7.2. Using the native query language of your NoSQL

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.

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.

7.3. Using Hibernate Search

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.

EntityManager entityManager =...//Add full-text superpowers to any EntityManager:FullTextEntityManager ftem =Search.getFullTextEntityManager(entityManager);//Optionally use the QueryBuilder to simplify Query definition:QueryBuilder b = ftem.getSearchFactory().buildQueryBuilder().forEntity(Hypothesis.class).get();//Create a LuceneQuery:Query lq = b.keyword().onField("description").matching("tomorrow").createQuery();//Transform the LuceneQuery in a JPA Query:FullTextQuery ftQuery = ftem.createFullTextQuery(lq,Hypothesis.class);//This is a requirement when using Hibernate OGM instead of ORM:ftQuery.initializeObjectsWith(ObjectLookupMethod.SKIP,DatabaseRetrievalMethod.FIND_BY_ID);//List all matching Hypothesis:List<Hypothesis> resultList = ftQuery.getResultList();

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).

The module names are
hibernate-ogm-infinispan, hibernate-ogm-ehcache, hibernate-ogm-mongodb, hibernate-ogm-neo4j and hibernate-ogm-couchdb.
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:

Note

When bootstrapping a session factory or entity manager factory programmatically,
you should use the constants declared on OgmProperties to specify configuration properties
such as hibernate.ogm.datastore.provider.

In this case you also can specify the provider in form of a class object of a datastore provider type
or pass an instance of a datastore provider type:

By default, a datastore provider chooses the best grid dialect transparently
but you can manually override that 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 and live a happier life instead.

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.

9.1.1. Adding Infinispan dependencies

If you’re not using a dependency management tool,
copy all the dependencies from the distribution in the directories:

/lib/required

/lib/infinispan

Optionally - depending on your container - you might need some of the jars from /lib/provided

9.1.2. Infinispan specific configuration properties

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.

Hibernate OGM properties for Infinispan

hibernate.ogm.datastore.provider

Set it to infinispan to use Infinispan as the datastore provider.

hibernate.ogm.infinispan.cachemanager_jndi_name

If you have an Infinispan EmbeddedCacheManager registered in JNDI,
provide the JNDI name and Hibernate OGM will use this instance
instead of starting a new CacheManager.
This will ignore any further configuration properties
as Infinispan is assumed being already configured.
Infinispan can typically be pushed to JNDI via WildFly, Spring or Seam.

hibernate.ogm.infinispan.configuration_resource_name

Should point to the resource name of an Infinispan configuration file.
This is ignored in case JNDI lookup is set.
Defaults to org/hibernate/ogm/datastore/infinispan/default-config.xml.

hibernate.ogm.datastore.keyvalue.cache_storage

The strategy for persisting data in Infinispan.
The following two strategies exist (values of the org.hibernate.ogm.datastore.keyvalue.options.CacheMappingType enum):

CACHE_PER_TABLE: A dedicated cache will be used for each entity type, association type and id source table.

CACHE_PER_KIND: Three caches will be used: one cache for all entities, one cache for all associations and one cache for all id sources.

Defaults to CACHE_PER_TABLE. It is the recommended strategy as it makes it easier to target a specific cache for a given entity.

Note

When bootstrapping a session factory or entity manager factory programmatically,
you should use the constants accessible via InfinispanProperties
when specifying the configuration properties listed above.

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

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

9.1.3. Cache names used by Hibernate OGM

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

store each entity type, association type and id source table in a dedicated cache
very much like what Hibernate ORM would do. This is the CACHE_PER_TABLE approach.

store data in three different caches when using the CACHE_PER_KIND approach:

ENTITIES: is going to be used to store the main attributes of all your entities.

ASSOCIATIONS: stores the association information representing the links between entities.

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.

9.2. Manage data size

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-core.jar includes a simple implementation
able to store data in simple binary files, on any read/write mounted filesystem;
this is an easy starting point, but the real stuff is to be found
in the additional modules found in the Infinispan distribution.
Here you can find many more implementations to store your data in anything
from JDBC connected relational databases, other NoSQL engines,
to cloud storage services or 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.

9.3. Clustering: store data on multiple Infinispan nodes

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:

Infinispan cache modes

local

Useful for a single VM: networking stack is disabled

replication

All data is replicated to each node;
each node contains a full copy of all entries.
Consequentially reads are faster but writes don’t scale as well.
Not suited for very large datasets.

distribution

Each entry is distributed on multiple nodes for redundancy and failure recovery,
but not to all the nodes.
Provides linear scalability for both write and read operations.
distribution is the default mode.

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 useful to let JGroups know which networking interface you want to use;
especially if you have multiple interfaces it might not guess correctly.

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:

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.

9.4. Storage principles

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.

9.4.1. Properties and built-in types

Each entity is represented by a map.
Each property or more precisely column is represented by an entry in this map,
the key being the column name.

Hibernate OGM support by default the following property types:

java.lang.String

java.lang.Boolean (or boolean primitive)

java.lang.Byte (or byte primitive)

java.lang.Long (or long primitive)

java.lang.Integer (or integer primitive)

java.lang.Double (or double primitive)

java.math.BigDecimal

java.math.BigInteger

java.util.Calendar

java.util.Date

java.util.UUID

java.util.URL

Note

Hibernate OGM doesn’t store null values in Infinispan,
setting a value to null is the same as removing the corresponding entry
from Infinispan.

This can have consequences when it comes to queries on null value.

9.4.2. Identifiers

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:

the identifier column names

the identifier column values

the entity table (for the CACHE_PER_KIND strategy)

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.

9.4.2.1. Identifier generation strategies

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.

Table 9.9. Content of the hibernate_sequences cache in CACHE_PER_TABLE

KEY

NEXT VALUE

["sequence_name"], ["song_sequence"]

11

Table 9.10. Content of the IDENTIFIERS cache in CACHE_PER_KIND

KEY

NEXT VALUE

"hibernate_sequences", "["sequence_name"], ["song_sequence"]

11

9.4.3. Entities

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:

the identifier column names

the identifier column values

the entity table (for the CACHE_PER_KIND strategy)

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.

9.5. Transactions

Infinispan supports transactions and integrates with any standard JTA TransactionManager;
this is a great advantage for JPA users as it allows to experience a similar behaviour
to the one we are used to when we work with RDBMS databases.

If you’re having Hibernate OGM start and manage Infinispan,
you can skip this as it will inject the same TransactionManager instance
which you already have set up in the Hibernate / JPA configuration.

If you are providing an already started Infinispan CacheManager instance
by using the JNDI lookup approach,
then you have to make sure the CacheManager is using the same TransactionManager
as Hibernate:

Infinispan supports different transaction modes like PESSIMISTIC and OPTIMISTIC,
supports XA recovery and provides many more configuration options;
see the Infinispan User Guide
for more advanced configuration options.

9.6. Storing a Lucene index in Infinispan

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:

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:

Table 9.52. Infinispan caches used to store indexes

Cache name

Description

Suggested cluster mode

LuceneIndexesLocking

Transfers locking information. Does not need a cache
store.

replication

LuceneIndexesData

Contains the bulk of Lucene data. Needs a cache
store.

distribution + L1

LuceneIndexesMetadata

Stores metadata on the index segments. Needs a cache
store.

replication

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 the main 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.

10.1. Configure Ehcache

Two steps:

Add the dependencies to classpath

And then choose one of:

Use the default Ehcache configuration (no action needed)

Point to your own configuration resource name

10.1.1. Adding Ehcache dependencies

To add the dependencies via some Maven-definitions-using tool,
add the following module:

If you’re not using a dependency management tool,
copy all the dependencies from the distribution in the directories:

/lib/required

/lib/ehcache

Optionally - depending on your container -
you might need some of the jars from /lib/provided

10.1.2. Ehcache specific configuration properties

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.

Ehcache datastore configuration properties

hibernate.ogm.datastore.provider

To use Ehcache as a datastore provider set it to ehcache.

hibernate.ogm.ehcache.configuration_resource_name

Should point to the resource name of an Ehcache configuration file.
Defaults to org/hibernate/ogm/datastore/ehcache/default-ehcache.xml.

hibernate.ogm.datastore.keyvalue.cache_storage

The strategy for persisting data in EhCache.
The following two strategies exist (values of the org.hibernate.ogm.datastore.keyvalue.options.CacheMappingType enum):

CACHE_PER_TABLE: A dedicated cache will be used for each entity type, association type and id source table.

CACHE_PER_KIND: Three caches will be used: one cache for all entities, one cache for all associations and one cache for all id sources.

Defaults to CACHE_PER_TABLE. It is the recommended strategy as it makes it easier to target a specific cache for a given entity.

Note

When bootstrapping a session factory or entity manager factory programmatically,
you should use the constants accessible via EhcacheProperties
when specifying the configuration properties listed above.

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

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

10.1.3. Cache names used by Hibernate OGM

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

store each entity type, association type and id source table in a dedicated cache
very much like what Hibernate ORM would do. This is the CACHE_PER_TABLE approach.

store data in three different caches when using the CACHE_PER_KIND approach:

ENTITIES: is going to be used to store the main attributes of all your entities.

ASSOCIATIONS: stores the association information representing the links between entities.

10.2.2.1. Identifier generation strategies

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.

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.mongodb.connection_timeout

Defines the timeout used by the driver
when the connection to the MongoDB instance is initiated.
This configuration is expressed in milliseconds.
The default value is 5000.

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.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):
ERRORS_IGNORED, 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.

Note

When bootstrapping a session factory or entity manager factory programmatically,
you should use the constants accessible via 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.

11.1.3. Annotation based configuration

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:

the write concern for entities and associations using the @WriteConcern annotation

the read preference for entities and associations using the @ReadPreference annotation

a strategy for storing associations using the @AssociationStorage and @AssociationDocumentStorage annotations
(refer to Section 11.2, “Storage principles” to learn more about these options).

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.

11.1.4. Programmatic 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:

write concern

read preference

association storage strategy

association document storage strategy

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.

11.2. Storage principles

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.

11.2.1. Properties and built-in types

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:

java.lang.String

{ "text" : "Hello world!" }

java.lang.Boolean (or boolean primitive)

{ "favorite" : true }

java.lang.Byte (or byte primitive)

{ "display_mask" : "70" }

java.lang.Long (or long primitive)

{ "userId" : NumberLong("-6718902786625749549") }

java.lang.Integer (or integer primitive)

{ "stockCount" : 12309 }

java.lang.Double (or double primitive)

{ "tax_percentage" : 12.34 }

java.math.BigDecimal

{ "site_weight" : "21.77" }

java.math.BigInteger

{ "site_weight" : "444" }

java.util.Calendar

{ "creation" : "2014/11/03 16:19:49:283 +0000" }

java.util.Date

{ "last_update" : ISODate("2014-11-03T16:19:49.283Z") }

java.util.UUID

{ "serialNumber" : "71f5713d-69c4-4b62-ad15-aed8ce8d10e0" }

java.util.URL

{ "url" : "http://www.hibernate.org/" }

java.util.URL

{ "url" : "http://www.hibernate.org/" }

java.util.URL

{ "url" : "http://www.hibernate.org/" }

org.bson.types.ObjectId

{ "object_id" : ObjectId("547d9b40e62048750f25ef77") }

Note

Hibernate OGM doesn’t store null values in MongoDB,
setting a value to null is the same as removing the field
in the corresponding object in the db.

This can have consequences when it comes to queries on null value.

11.2.2. Entities

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.

11.2.2.1. Identifiers

Note

Hibernate OGM always store identifiers using the _id field of a MongoDB document ignoring
the name of the property in the entity.

That’s a good thing as MongoDB has special treatment and expectation of the property _id.

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.

Warning

Care must be taken when using the GenerationType.AUTO strategy.
When the property hibernate.id.new_generator_mappings is set to false (default),
it will map to the IDENTITY strategy.
As described before, this requires your ids to be of type ObjectId or @Type(type = "objectid") String.
If hibernate.id.new_generator_mappings is set to true, AUTO will be mapped to the TABLE strategy.
This requires your id to be of a numeric type.

We recommend to not use AUTO but one of the explicit strategies (IDENTITY or TABLE) to avoid
potential misconfigurations.

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.

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.

11.2.3.1. In Entity strategy

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.

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:

Runner collection

11.2.3.4. One collection per association strategy

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.

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)

Example 11.42. Bidirectional many-to-many using one collection per association strategy and @JoinTable

11.2.3.5. Global collection strategy

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.

11.3. Transactions

MongoDB does not support transactions.
Only changes applied to the same document are done atomically.
A change applied to more than one document will not be applied atomically.
This problem is slightly mitigated by the fact that Hibernate OGM queues all changes
before applying them during flush time.
So the window of time used to write to MongoDB is smaller than what you would have done manually.

We recommend that you still use transaction demarcations with Hibernate OGM
to trigger the flush operation transparently (on commit).
But do not consider rollback as a possibility, this won’t work.

11.4. Optimistic Locking

MongoDB does not provide a built-in mechanism for detecting concurrent updates to the same document
but it provides a way to execute atomic find and update operations.
By exploiting this commands Hibernate OGM can detect concurrent modifications to the same document.

You can enable optimistic locking detection using the annotation @Version:

The @Version annotation define which attribute will keep track of the version of the document,
Hibernate OGM will update the field when required and if two changes from two different sessions (for example)
are applied to the same document a org.hibernate.StaleObjectStateException is thrown.

You can use @Column to change the name of the field created on MongoDB:

11.5. Queries

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.

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 such as MongoDB
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.

11.5.1. JP-QL queries

Hibernate OGM is a work in progress, so only a sub-set of JP-QL constructs is available
when using the JP-QL query support. This includes:

simple comparisons using "<", "⇐", "=", ">=" and ">"

IS NULL and IS NOT NULL

the boolean operators AND, OR, NOT

LIKE, IN and BETWEEN

ORDER BY

Queries using these constructs will be transformed into equivalent native MongoDB queries.

Note

11.5.2. Native MongoDB queries

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

find queries specifying the search criteria only

queries specified using the MongoDB CLI syntax

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.

Warning

Specifying native MongoDB queries using the CLI syntax is an EXPERIMENTAL feature for the time being.
Currently only find() and count() queries are supported via the CLI syntax.
Further query types (including updating queries) may be supported in future revisions.

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

JSON parameters passed via the CLI syntax must be specified using the strict mode
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.

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.

11.5.3. Hibernate Search

You can index your entities using Hibernate Search.
That way, a set of secondary indexes independent of MongoDB is maintained by Hibernate Search
and you can write queries on top of them.
The benefit of this approach is a nice integration at the JPA / Hibernate API level
(managed entities are returned by the queries).
The drawback is that you need to store the Lucene indexes somewhere
(file system, infinispan grid, etc).
Have a look at the Infinispan section (Section 9.6, “Storing a Lucene index in Infinispan”)
for more info on how to use Hibernate Search.

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.

12.2. Configuring Neo4j

The absolute path representing the location of the Neo4j database. Example: C:\neo4jdb\mydb

hibernate.ogm.neo4j.configuration_resource_name (optional)

Location of the Neo4j embedded properties file. It can be an URL, name of a classpath resource or file system path.

hibernate.schema_update.unique_constraint_strategy (optional)

If set to SKIP, Hibernate OGM won’t create any unique constraints on the nodes representing the entities.
This property won’t affect the unique constraints generated for sequences.
Other possible values (defined on the org.hibernate.tool.hbm2ddl.UniqueConstraintSchemaUpdateStrategy enum) are DROP_RECREATE_QUIETLY and RECREATE_QUIETLY
but the effect will be the same (since Neo4j constraints don’t have a name):
keep the existing constraints and create the missing one.
Default value is DROP_RECREATE_QUIETLY.

Warning

At the moment, you must not specify the property hibernate.transaction.jta.platform when using Neo4j.
It would override Hibernate OGM’s version and the transactions would not work correctly.

Note

Use the following method to retrieve the transaction manager
(it needs to be done after the EntityManagerFactory has been bootstrapped):

Note

When bootstrapping a session factory or entity manager factory programmatically,
you should use the constants accessible via Neo4jProperties
when specifying the configuration properties listed above.

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

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

12.3. Storage principles

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.

12.3.1. Properties and built-in types

Each entity is represented by a node.
Each property or more precisely column is represented by an attribute of this node.

The following types (and corresponding primitives) get passed to Neo4j without any conversion:

java.lang.Boolean

java.lang.Byte

java.lang.Character

java.lang.Double

java.lang.Float

java.lang.Integer

java.lang.Long

java.lang.String

The following types get converted into java.lang.String:

java.math.BigDecimal

java.math.BigInteger

java.util.Calendar

stored as +String+ with the format "yyyy/MM/dd HH:mm:ss:SSS Z"

java.util.Date

stored as +String+ with the format "yyyy/MM/dd HH:mm:ss:SSS Z"

java.util.UUID

java.util.URL

Note

Hibernate OGM doesn’t store null values in Neo4J,
setting a value to null is the same as removing the corresponding entry
from Neo4J.

This can have consequences when it comes to queries on null value.

12.3.2. Entities

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.

12.3.2.1. Identifiers and unique constraints

Warning

Neo4j does not support constraints on more than one property.
For this reason, Hibernate OGM will create a unique constraint ONLY when it spans
a single property and it will ignore the ones spanning multiple properties.

The lack of unique constraints on node properties might result in the creation of multiple
nodes with the same identifier.

Hibernate OGM will create unique constraints for the identifier of entities and for the properties
annotated with:

12.3.3. Associations

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.

12.3.4. Auto-generated Values

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.

12.4. Transactions

Neo4j operations can be executed only inside a transaction.
Unless a different org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform is specified, OGM will use a specific implementation to integrate with the Neo4j transaction mechanism.
This means that you can start and commit transaction using the Hibernate session.

The drawback is that it is not possible at the moment to let Neo4j participate in managed JTA transactions spanning several resources (see issue OGM-370).

12.5. Queries

You can express queries in a few different ways:

using JP-QL

using the Cypher query language

Note

Neo4J makes use of a Lucene version which
is not compatible with the most recent Hibernate Search version.
This unfortunately makes it impossible to use the latest Hibernate Search version
and Neo4J embedded in the same application.

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.

12.5.1. JP-QL queries

Hibernate OGM is a work in progress, so only a sub-set of JP-QL constructs is available
when using the JP-QL query support. This includes:

simple comparisons using "<", "⇐", "=", ">=" and ">"

IS NULL and IS NOT NULL

the boolean operators AND, OR, NOT

LIKE, IN and BETWEEN

ORDER BY

Queries using these constructs will be transformed into equivalent Cypher queries.

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 of the fact that partial updates are unsupported at the moment
(OGM-388).
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 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.

13.1. Configuring CouchDB

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

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.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.

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.

13.1.1. Annotation based configuration

Hibernate OGM allows to configure store-specific options via Java annotations.
When working with the CouchDB backend, you can specify how associations should be stored
using the AssociationStorage annotation
(refer to Section 13.2, “Storage principles” to learn more about association storage strategies in general).

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.

13.1.2. Programmatic 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 CouchDB, you can currently configure the following options using the API:

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.

13.2. Storage principles

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.

13.2.1. Properties and built-in types

Note

Hibernate OGM doesn’t store null values in CouchDB,
setting a value to null will be the same as removing the field
in the corresponding object in the db.

Hibernate OGM support by default the following types:

java.lang.String

{ "text" : "Hello world!" }

java.lang.Boolean (or boolean primitive)

{ "favorite" : true }

java.lang.Byte (or byte primitive)

{ "display_mask" : "70" }

java.lang.Long (or long primitive)

{ "userId" : "-6718902786625749549" }

java.lang.Integer (or integer primitive)

{ "stockCount" : 12309 }

java.lang.Double (or double primitive)

{ "tax_percentage" : 12.34 }

java.math.BigDecimal

{ "site_weight" : "21.77" }

java.math.BigInteger

{ "site_weight" : "444" }

java.util.Calendar

{ "creation" : "2014-11-18T15:51:26.252Z" }

java.util.Date

{ "last_update" : "2014-11-18T15:51:26.252Z" }

java.util.UUID

{ "serialNumber" : "71f5713d-69c4-4b62-ad15-aed8ce8d10e0" }

java.util.URL

{ "url" : "http://www.hibernate.org/" }

13.2.2. Entities

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.

Warning

Not mapping the _rev attribute may cause lost updates,
as Hibernate OGM needs to re-read the current revision before doing an update in this case.
Thus a warning will be issued during initialization for each entity type which fails to map that property.

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.

13.2.2.1. Identifiers

The _id field of a CouchDB document is directly used
to store the identifier columns mapped in the entities.
You can use any persistable Java type as identifier type, e.g. String or long.

Hibernate OGM will convert the @Id property into a _id document field
so you can name the entity id like you want, it will always be stored into _id.

Note that you also can work with embedded ids (via @EmbeddedId),
but be aware of the fact that CouchDB doesn’t support storing embedded structures in the _id attribute.
Hibernate OGM thus will create a concatenated representation of the embedded id’s properties in this case.

13.2.3.1. In Entity strategy

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.

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
???).

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:

13.2.3.2. Association document strategy

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.