Library to work with Hibernate by fluent API
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
config Update fluent_hibernate_formatter.xml Sep 30, 2015
fluent-hibernate-core/src A preparation for the 0.3.1 release Sep 8, 2016
fluent-hibernate-examples Fix hibernate-context.xml in spring-console. Jun 23, 2016
gradle/wrapper Update gradle to 2.13 May 12, 2016
.gitattributes Onew gradle project to all fluent projects Sep 23, 2015
.gitignore Update gradle to 2.13 May 12, 2016
.travis.yml
LICENSE.md Update build to include deploy task Sep 26, 2015
README.md
_build.bat
_check.bat Onew gradle project to all fluent projects Sep 23, 2015
_prepare_Eclipse.bat Onew gradle project to all fluent projects Sep 23, 2015
build.gradle A preparation for the 0.3.1 release Sep 8, 2016
gradle.properties Fix props in gradle Sep 26, 2015
gradlew Adapter to use Hibernate 4 naming strategies with Hibernate 5 Jun 21, 2016
gradlew.bat Add gradle building system. Sep 23, 2015
gui-wrapper.bat
gui.bat Update gradle to 2.13 May 12, 2016
settings.gradle Add a new example project spring-console. It is just a template now. Oct 16, 2015

README.md

fluent-hibernate

A library to work with Hibernate by fluent API. This library hasn't dependencies, except Hibernate libraries. It requires Java 1.6 and above. It can be used with Hibernate 5 and Hibernate 4.

Build Status

Download

Direct link

Release 0.3.1

Maven (pom.xml)
<dependency>
  <groupId>com.github.v-ladynev</groupId>
  <artifactId>fluent-hibernate-core</artifactId>
  <version>0.3.1</version>
</dependency>

All versions in the Maven repository: fluent-hibernate-core

Gradle (build.gradle)
compile 'com.github.v-ladynev:fluent-hibernate-core:0.3.1'

Hibernate 4 Notes

If you want to use the library with Hibernate 4, you can consider to exclude a transitive dependency to Hibernate 5. For example, using Gradle:

    compile('com.github.v-ladynev:fluent-hibernate-core:0.3.1') {
        exclude group: 'org.hibernate'
    }

The Most Useful Features

fluent-hibrnate has features which can be used with plain Hibernate or Spring code without a library infrastructure.

Scan the Class Path for Hibernate Entities

The library can be used for a quick entities scanning. You will need just the library jar, without additional dependencies. Just download the library using Download section and use EntityScanner:

For Hibernate 4 and Hibernate 5

Configuration configuration = new Configuration();
EntityScanner.scanPackages("my.com.entities", "my.com.other.entities")
    .addTo(configuration);
SessionFactory sessionFactory = configuration.buildSessionFactory();

Using a new Hibernate 5 bootstrapping API

List<Class<?>> classes = EntityScanner
        .scanPackages("my.com.entities", "my.com.other.entities").result();

MetadataSources metadataSources = new MetadataSources();
for (Class<?> annotatedClass : classes) {
    metadataSources.addAnnotatedClass(annotatedClass);
}

SessionFactory sessionFactory = metadataSources.buildMetadata()
    .buildSessionFactory();

Hibernate 5 Implicit Naming Strategy

It generates table and column names with underscores, like ImprovedNamingStrategy from Hibernate 4 and Hibernate 3, and constraint names (unique, foreign key) as well. Apart those, it has a lot of configurable interesting features like: plural table names, table and column prefixes, embedded column prefixes via the custom @FluentName annotation, automatic name restriction (by removing the vowels) and others.

Just download the library using Download section and use Hibernate5NamingStrategy:

Configuration configuration = new Configuration();
configuration.setImplicitNamingStrategy(new Hibernate5NamingStrategy());
SessionFactory sessionFactory = configuration.configure().buildSessionFactory();

Using strategy options for a tables prefix and a names restriction except the join table names

Configuration configuration = new Configuration();
configuration.setImplicitNamingStrategy(
        new Hibernate5NamingStrategy(StrategyOptions.builder().tablePrefix("acps")
                .restrictLength(50).restrictJoinTableNames(false).build()));
SessionFactory sessionFactory = configuration.configure().buildSessionFactory();

Using Spring

<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
  <property name="implicitNamingStrategy">
    <bean class="com.github.fluent.hibernate.cfg.strategy.hibernate5.Hibernate5NamingStrategy">
      <property name="options">
        <bean class="com.github.fluent.hibernate.cfg.strategy.StrategyOptions">
          <property name="tablePrefix" value="acps" />
          <property name="maxLength" value="50" />
          <property name="restrictJoinTableNames" value="false" />
        </bean>
      </property>
    </bean>
  </property>
</bean>

ImprovedNamingStrategy for Hibernate 5

It is imposible to use Hibernate 4 naming strategies, for an example org.hibernate.cfg.ImprovedNamingStrategy, with Hibernate 5 (HHH-10155). To continue using ImprovedNamingStrategy functionality with Hibernate 5 ImprovedNamingStrategyHibernate5 can be used. Apart an ImprovedNamingStrategy behaviour, ImprovedNamingStrategyHibernate5 provides generation of foreign key and unique constraint names like Hibernate 4 does (with some limitations, see below).

Just pass ImprovedNamingStrategyHibernate5 to the Hibernate 5 configuration. ImprovedNamingStrategyHibernate5 implements the ImplicitNamingStrategy interface, so you can place it everywhere ImplicitNamingStrategy can be placed.

For an example, using Configuration:

Configuration configuration = new Configuration();
configuration.setImplicitNamingStrategy(ImprovedNamingStrategyHibernate5.INSTANCE);
SessionFactory sessionFactory = configuration.configure().buildSessionFactory();

ImprovedNamingStrategyHibernate5 can be used with JPA configuration as well.

Limitations of ImprovedNamingStrategy for Hibernate 5

Keep in mind, that ImprovedNamingStrategyHibernate5 has some limitations are described below. I think, that these limitations can be encountered in rarely situations. If you have problems with these situations fill free to create an issue or make a pull request.

I used ImprovedNamingStrategyHibernate5Test to test the strategy. To check an ImprovedNamingStrategy behaviour with Hibernate 4 I used this unit test: ImprovedNamingStrategyTest.

Constraint Names Generation

Foreign key and unique constraint names are generated by Hibernate 5 are slightly different from ones are generated by Hibernate 4.

I implement a Hibernate 4 behaviour in ImprovedNamingStrategyHibernate5, but Hibernate 5 doesn't always use a naming strategy to generate unique constraint names. For an, example: a unique constraint for @OneToMany annotation using a join table and @Column(unique = true) don't use ImplicitNamingStrategy. You need to delete such unique constraint names yourself, before Hibernate 5 will update a schema.

@DiscriminatorColumn Name Generation

Hibernate 5 doesn't use a naming strategy to generate such names, because of an issue. Hiibernate 5 generates DTYPE name for the discriminator column. Hibernate 4 uses ImprovedNamingStrategy#columnName() to convert DTYPE to dtype. You need to provide explicit names in such situation.

@OrderColumn Name Generation

Hibernate 5 doesn't use a naming strategy to generate such names, because of an issue. Hibernate 5 generates booksOrdered_ORDER, opposite books_ordered_order is generated by Hibernate 4 ImprovedNamingStrategy. You need to provide explicit names in such situation.

@MapKeyColumn Name Generation

Hibernate 5 doesn't use a naming strategy to generate such names, because of an issue. Hibernate 5 generates booksMap_KEY, opposite books_map_key is generated by Hibernate 4 ImprovedNamingStrategy. You need to provide explicit names in such situation.

Other Artifacts Name Generation

There are some methods in the ImplicitNamingStrategy are not used by Hibernate 5 to generate names. And there are some methods for which I can't represent unit tests. All these methods throw UnsupportedOperationException. The list of methods below

    Identifier determineTenantIdColumnName(ImplicitTenantIdColumnNameSource source);

    Identifier determineIdentifierColumnName(ImplicitIdentifierColumnNameSource source);

    Identifier determinePrimaryKeyJoinColumnName(ImplicitPrimaryKeyJoinColumnNameSource source);

    Identifier determineAnyDiscriminatorColumnName(ImplicitAnyDiscriminatorColumnNameSource source);

    Identifier determineAnyKeyColumnName(ImplicitAnyKeyColumnNameSource source);

Hibernate4To5NamingStrategyAdapter

This adapter can be used to adapt Hibernate 4 naming strategies to Hibernate 5 ImplicitNamingStrategy. ImprovedNamingStrategy for Hibernate 5 is builded on top of it. So it has the same limitations.

You can use the adapter by this way:

Configuration configuration = new Configuration();
configuration.setImplicitNamingStrategy(new Hibernate4To5NamingStrategyAdapter(EJB3NamingStrategy.INSTANCE));
SessionFactory sessionFactory = configuration.configure().buildSessionFactory();

It can be used with JPA configuration as well. Probably, you will need to extend Hibernate4To5NamingStrategyAdapter similar as ImprovedNamingStrategyHibernate5 extends it.

Nested Transformer

It is a custom transformer like Transformers.aliasToBean(SomeDto.class), but with the nested projections support.

Just download the library using Download section and use FluentHibernateResultTransformer.

Load User only with login and department.name fields

@Entity
@Table(name = "users")
public class User {

    @Id
    @Column(name = "pid")
    private Long pid;

    @Column(name = "login")
    private String login;

    @ManyToOne
    @JoinColumn(name = "fk_department")
    private Department department;

}

@Entity
@Table(name = "departments")
public class Department {

    @Id
    @Column(name = "pid")
    private Long pid;

    @Column(name = "name")
    private String name;

}

Criteria criteria = session.createCriteria(User.class, "u");
criteria.createAlias("u.department", "d", JoinType.LEFT_OUTER_JOIN);
criteria.setProjection(Projections.projectionList()
        .add(Projections.property("u.login").as("login"))
        .add(Projections.property("d.name").as("department.name")));

List<User> users = criteria
        .setResultTransformer(new FluentHibernateResultTransformer(User.class))
        .list();

Please, don't forget to specify projection aliases.

Using With Native SQL

It is impossible with Hibernate 5 to use Transformers.aliasToBean(SomeDto.class) the same way as it is used with Hibernate 3 — without the aliases with the quotes (a more deep explanation), but it is possible using FluentHibernateResultTransformer. This code works pretty well:

List<User> users = session.createSQLQuery("select login from users")
        .setResultTransformer(new FluentHibernateResultTransformer(User.class))
        .list();

The transformer can be used for a native SQL with the nested projections (opposite HQL). It is need to use the aliases with the quotes in this case:

String sql = "select u.login, d.name as \"department.name\" "
        + "from users u left outer join departments d on u.fk_department = d.pid";
List<User> users = session.createSQLQuery(sql)
        .setResultTransformer(new FluentHibernateResultTransformer(User.class))
        .list();

Ignore Alias Duplicates

Sometimes it is convenient using complex search criteries to add an alias multiple times. In such situations Hibernate generates the org.hibernate.QueryException: duplicate alias exception . There is a utility class to solve this problem: Aliases. This code with alias duplicates working without errors:

Criteria criteria = session.createCriteria(User.class, "u");
Aliases aliases = Aliases.create()
        .add("u.department", "d", JoinType.LEFT_OUTER_JOIN)
        .add("u.department", "d", JoinType.LEFT_OUTER_JOIN);

criteria.add(Restrictions.isNotNull("d.name"));
aliases.addToCriteria(criteria);
List<User> users = criteria.list();

Examples

Get all users

List<User> users = H.<User> request(User.class).list();

Getting a user with a login my_login

final String loginToFind = "my_login";
User user = H.<User> request(User.class).eq("login", loginToFind).first();

A partial objects loading

Get all users, but only with login and id properties are filled (other properties will be null).

List<User> users = H.<User> request(User.class).proj("login").proj("id")
    .transform(User.class).list();

Example Projects

Contributors

Dependency Status

Dependency Status

Progress

Throughput Graph

TODO:

Stories in Ready In Progress