== Hibernate

https://hibernate.org/orm/[Hibernate ORM] module. 

=== Usage

1) Add the dependencies (hikari + hibernate):

[dependency, artifactId="jooby-hikari:DataSource via HikariCP, jooby-hibernate:Hibernate Module"]
.

2) Add database driver (mySQL here):

[dependency, groupId="mysql", artifactId="mysql-connector-java", version="${mysql-connector-java.version}"]
.

3) Set database properties

.application.conf
[source, properties]
----
db.url = "jdbc:mysql://localhost/mydb"
db.user = myuser
db.password = mypass
----


4) Install and use Hibernate

.Java
[source, java, role="primary"]
----
import io.jooby.hikari.HikariModule;
import io.jooby.hibernate.HibernateModule;
{
  install(new HikariModule());                        <1>

  install(new HibernateModule());                     <2>
  
  get("/", ctx -> {
    EntityManager em = require(EntityManager.class);  <3>
    Transaction trx = em.getTransaction();            <4>
    try {
      trx.begin();                                    <5>
      
      // work with EntityManager compute a result     <6>
      
      trx.commit();                                   <7>
      
      return result;
    } catch(Exception x) {
      trx.rollback();                                 <8>
      throw x;
    } finally {
      em.close();                                     <9>
    }
  });
}
----

.Kotlin
[source, kt, role="secondary"]
----
import io.jooby.hikari.HikariModule
import io.jooby.hibernate.HibernateModule

{
  install(HikariModule())                             <1>
  
  install(new HibernateModule())                      <2>
  
  get("/") {
    val em = require(EntityManager::class)            <3>
    val trx = em.getTransaction()                     <4>
    try {
      trx.begin()                                     <5>
      
      // work with EntityManager compute a result     <6>
      
      trx.commit()                                    <7>
      
      result
    } catch(Exception x) {
      trx.rollback()                                  <8>
      throw x
    } finally {
      em.close()                                      <9>
    }
  }
}
----

<1> Install and creates a `DataSource`
<2> Install and initializes Hibernate. Entities are automatically detected
<3> Get a new `EntityManager`
<4> Creates a new transaction
<5> Being the transaction
<6> Work with EntityManager (read, write to database)
<7> Commit the transaction
<8> Rollback transaction in case of error
<9> Close the `EntityManager` 

=== Entity Discovering

By default the javadoc:hibernate.HibernateModule[artifact="jooby-hibernate"] module detects all the persistent entities under javadoc:Jooby[getBasePackage, text = "base/root package"]. The module provides two
options for more explicit control:

- List persistent classes at creation time:

----
  install(new HibernateModule(MyEntity1.class, MyEntity2.class));
----

- Explicit package scanning

----
  install(new HibernateModule().scan("mypackage"));
----

=== Transactional Request

The javadoc:hibernate.TransactionalRequest[artifact="jooby-hibernate"] filter takes care of a lifecycle of an `EntityManager`/`StatelessSession` per HTTP request.
The filter creates, bind, begin/commit/rollback transaction and finally close it, so route handler
doesn't have to deal with that boring lines of code.

.TransactionalRequest
[source, java, role = "primary"]
----
import io.jooby.hikari.HikariModule;
import io.jooby.hibernate.HibernateModule;
import io.jooby.hibernate.TransactionalRequest;

{
  install(new HikariModule());
  
  install(new HibernateModule());
  
  use(new TransactionalRequest());
  
  post("/create", ctx -> {
    EntityManager em = require(EntityManager.class);
    
    MyEntity e = ...;
    
    em.persist(e);

    return e;
  });
}
----

.Kotlin
[source, kt, role="secondary"]
----
import io.jooby.hikari.HikariModule
import io.jooby.hibernate.HibernateModule
import io.jooby.hibernate.TransactionalRequest

{
  install(HikariModule())
  
  install(HibernateModule())
  
  use(TransactionalRequest())
  
  post("/create") { ctx ->
    val em = require(EntityManager::class)
    
    val e = ...
    
    em.persist(e)

    e
  }
}
----

.TransactionalRequest with StatelessSession
[source, java, role = "primary"]
----
import io.jooby.hikari.HikariModule;
import io.jooby.hibernate.HibernateModule;
import io.jooby.hibernate.TransactionalRequest;

{
  install(new HikariModule());
  
  install(new HibernateModule());
  
  use(new TransactionalRequest().useStatelessSession());
  
  post("/create", ctx -> {
    StatelessSession session = require(StatelessSession.class);
    
    MyEntity e = ...;
    
    session.insert(e);

    return e;
  });
}
----

.Kotlin
[source, kt, role="secondary"]
----
import io.jooby.hikari.HikariModule
import io.jooby.hibernate.HibernateModule
import io.jooby.hibernate.TransactionalRequest

{
  install(HikariModule())
  
  install(HibernateModule())
  
  use(TransactionalRequest().useStatelessSession())
  
  post("/create") { ctx ->
    val session = require(StatelessSession::class)
    
    val e = ...
    
    session.insert(e)

    e
  }
}
----

The `EntityManager`/`StatelessSession` is tied to the current HTTP request. Multiple `require`/`injection` calls produce
the same `EntityManager`/`StatelessSession`. It is a simple way of managed simple read/write operations.

[NOTE]
====
The javadoc:hibernate.TransactionalRequest[artifact="jooby-hibernate"] doesn't extend session to the rendering phase (json, html, etc.).
The route handler needs to make sure all the information required by the rendering phase is available.
Otherwise, you are going to see `LazyInitializationException`.
====

There is a javadoc:hibernate.SessionRequest[artifact="jooby-hibernate"] filter that works identically but leaves transaction
management to you, so no transaction is started/committed or rollback during a HTTP request.

==== @Transactional

If you simply install the decorator it becomes enabled by default, this means that each route in its
scope become transactional. You can exclude an MVC route by annotating it with the
javadoc:annotation.Transactional[] annotation:

.@Transactional
[source,java,role = "primary"]
----
import io.jooby.annotation.Transactional;

@Transactional(false)
@GET("/")
public void get(Context ctx) {
  // no automatic transaction management here
}
----

.Kotlin
[source, kt, role="secondary"]
----
import io.jooby.annotation.Transactional

@Transactional(false)
@GET("/")
fun get(ctx: Context) {
  // no automatic transaction management here
}
----

You also have the option to invert this logic by disabling the decorator by default:

.TransactionalRequest disabled by default
[source, java, role = "primary"]
----
import io.jooby.ebean.TransactionalRequest;

{
  ...
  use(new TransactionalRequest().enabledByDefault(false));
  ...
}
----

.Kotlin
[source, kt, role="secondary"]
----
import io.jooby.ebean.TransactionalRequest

{
  ...
  use(TransactionalRequest().enabledByDefault(false))
  ...
}
----

Then you can enable it for the selected routes using `@Transactional(true)`:

.@Transactional
[source,java,role = "primary"]
----
import io.jooby.annotation.Transactional;

@Inject
private EntityManager entityManager;

@Transactional(true)
@GET("/")
public void get(Context ctx) {
  // work with EntityManager
}
----

.Kotlin
[source, kt, role="secondary"]
----
import io.jooby.annotation.Transactional

@Inject
private lateinit var entityManager: EntityManager

@Transactional(true)
@GET("/")
fun get(ctx: Context) {
  // work with EntityManager
}
----

This feature is not limited to MVC routes. For script routes use the constant `Transactional.ATTRIBUTE`:

.Transactional for script routes
[source,java,role = "primary"]
----


{
  get("/", ctx -> {
    ...
  }).attribute(Transactional.ATTRIBUTE, false);
}
----

.Kotlin
[source, kt, role="secondary"]
----
import io.jooby.annotation.Transactional

{
  get("/") {
    ...
  }).attribute(Transactional.ATTRIBUTE, false);
}
----

The behavior of the `SessionRequest` decorator is not affected by `@Transactional`.

=== UnitOfWork

Another way of managing the lifecycle of an EntityManager and transactions is working with an instance
of `UnitOfWork`. You may acquire one from the service registry or inject it via DI.

Usage:

.UnitOfWork
[source, java, role = "primary"]
----
{
  get("/pets", ctx -> require(UnitOfWork.class)
      .apply(em -> em.createQuery("from Pet", Pet.class).getResultList()));
}
----

.Kotlin
[source, kt, role="secondary"]
----
{
  get("/pets") {
    require(UnitOfWork::class.java)
        .apply { em ->
          em.createQuery("from Pet", Pet::class.java).resultList
        }
  }
}
----

`UnitOfWork` automatically begins a transaction. After the code block passed to `apply(...)` or `accept(...)`
returns the transaction is being committed and the `EntityManager` closed.

If the code block throws an exception, the transaction is rolled back, and the `EntityManager` is released as well.
You may access a `UnitOfWork.TransactionHandler` instance to be able to work with multiple transactions:

.Multiple transactions
[source, java, role = "primary"]
----
{
  get("/update", ctx -> require(UnitOfWork.class)
      .apply((em, txh) -> {
        em.createQuery("from Pet", Pet.class).getResultList().forEach(pet -> {
          pet.setName(pet.getName() + " Updated");
          txh.commit(); // update each entity in a separate transaction
        });
        return "ok";
      }));
}
----

.Kotlin
[source, kt, role="secondary"]
----
{
  get("/update") {
    require(UnitOfWork::class.java)
        .apply { em, txh ->
          em.createQuery("from Pet", Pet::class.java).resultList.forEach { pet ->
            pet.name = "${pet.name} Updated"
            txh.commit() // update each entity in a separate transaction
          }
          "ok"
        }
  }
}
----

A call to `UnitOfWork.TransactionHandler.commit()` commits the current transaction and automatically begins a new one.
Similarly, you can issue a rollback using `UnitOfWork.TransactionHandler.rollback()` which also begins a new transaction
after rolling back the current one.

`UnitOfWork` does *not* allow nesting:

[source, java]
----
{
  get("/nope", ctx -> require(UnitOfWork.class)
      .apply(em -> {

        // will lead to exception
        require(UnitOfWork.class).accept(...);

        return "ok";
      }));
}
----

Neither can it be used together with `SessionRequest` or `TransactionalRequest`:

[source, java]
----
{
  use(new TransactionalRequest());

  // will lead to exception
  get("/nope", ctx -> require(UnitOfWork.class)
      .apply(em -> em.createQuery("from Pet", Pet.class).getResultList()));
}
----

=== Schema Creation

Schema creation is controlled by the `hibernate.hbm2ddl.auto` property. The Hibernate module configure this property using the following rules:

- When the javadoc:flyway.FlywayModule[artifact="jooby-flyway"] module is present, the value of `hibernate.hbm2ddl.auto` is set to `none`
- When `application.env` property is set to `dev` or `test`, the value of `hibernate.hbm2ddl.auto` is set to `update`
- Otherwise is set to `none`

=== Advanced Options

Advanced Hibernate configuration is supported from application configuration properties.

.application.conf
[source, properties]
----
hibernate.hbm2ddl.auto = create
----

Or by providing a custom javadoc:hibernate.HibernateConfigurer[artifact="jooby-hibernate"] instance. The javadoc:hibernate.HibernateConfigurer[artifact="jooby-hibernate"] 
let you hook and customize Hibernate bootstrap process:

.HibernateConfigurer:
[source, java]
----
import io.jooby.hibernate.HibernateConfigurer;

public class MyConfigurer extends HibernateConfigurer {
  /**
   * Hook into bootstrap registry and customize it.
   *
   * @param builder Builder.
   * @param config Configuration.
   */ 
  public void configure(BootstrapServiceRegistryBuilder builder, Config config) {
  }

  /**
   * Hook into service registry and customize it.
   *
   * @param builder Builder.
   * @param config Configuration.
   */
  public void configure(StandardServiceRegistryBuilder builder, Config config) {
  }

  /**
   * Hook into metadata sources and customize it.
   *
   * @param sources Sources.
   * @param config Configuration.
   */
  public void configure(MetadataSources sources, Config config) {
  }

  /**
   * Hook into metadata builder and customize it.
   *
   * @param builder Builder.
   * @param config Configuration.
   */
  public void configure(MetadataBuilder builder, Config config) {
  }

  /**
   * Hook into SessionFactory creation and customize it.
   *
   * @param builder Builder.
   * @param config Configuration.
   */
  public void configure(SessionFactoryBuilder builder, Config config) {
  }
}

{
  install(new HibernateModule().with(new MyConfigurer()));
}
----

Something similar is possible for custom Session using a javadoc:hibernate.SessionProvider[artifact="jooby-hibernate"]:

.SessionProvider
[source, java]
----
{
  install(new HibernateModule().with(builder -> {
    return builder
     .flushMode(AUTO)
     .openSession();
  }));
}
----
