Only this pageAll pages
Powered by GitBook
1 of 24

BXORM 1.x

Loading...

Loading...

Loading...

Loading...

Getting Started

Loading...

Loading...

Loading...

Loading...

Loading...

Modeling

Loading...

Loading...

Loading...

Loading...

Usage

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

External Links

Introduction

The BoxLang ORM module allows your BoxLang application to integrate with the powerful Hibernate ORM

BoxLang ORM

class entityName="Auto" persistent="true" {

	property name="id" type="string" fieldtype="id" ormtype="string";
	property name="make" type="string";
	property name="model" type="string";

    function onPreInsert(){
        log.info( "Inserting new Auto: #getMake()# #getModel()#" );
    }
}

BoxLang ORM also enables transactional persistence, where an error during a save will roll back the entire transaction to prevent leaving the database in a broken state:

transaction{
    try{
        entitySave(
            entityNew( "Purchase", {
                productID : "123-expensive-watch",
                purchaseTime : now(),
                customerID : customer.getId()
            })
        );
        var cartProducts = entityLoad( "CartProduct", customer.getID() );
        entityDelete( cartProducts );
    } catch ( any e ){
        // don't clear the user's cart if the purchase failed
        transactionRollback();
        rethrow;
    }
}

Hibernate Version Support

bx-orm bundles Hibernate 5.6.15.FINAL.

Open Source Product

Features In A Nutshell

  • Add Object Relational Mapping to any boxlang app with Hibernate ORM

  • Use native built-in-functions (BIFs) to update and persist entities to the database (entityNew(), entitySave(), ormFlush(), etc.)

  • Supports 80+ database dialects, from SQLServer2005 to MySQL8 and PostgreSQL

  • Generate your mapping XML once and never again with the autoGenMap=false ORM configuration setting

  • React to entity changes with pre and post event listeners such as onPreInsert(), onPreUpdate() and onPreDelete()

  • Over 20 native BIFs:

    • EntityDelete()

    • EntityLoad()

    • EntityLoadByExample()

    • EntityLoadByPK()

    • EntityMerge()

    • EntityNameArray()

    • EntityNameList()

    • EntityNew()

    • EntityReload()

    • EntitySave()

    • EntityToQuery()

    • ORMClearSession()

    • ORMCloseAllSessions()

    • ORMEvictCollection()

    • ORMEvictEntity()

    • ORMEvictQueries()

    • ORMExecuteQuery()

    • ORMFlush()

    • ORMGetSession()

    • ORMGetSessionFactory()

    • ORMReload()

Support

The allows your BoxLang application to integrate with the powerful . With Hibernate, you can interact with your database records in an object oriented fashion, using a BoxLang class to denote each record and simple getters and setters for each field value:

bx-orm is an open source BoxLang module with no license purchase necessary. If you are looking to further the development of this extension, consider .

By launching we are able to give back to the community, as well as offer premium support to enterprises looking for a level up in their Hibernate implementations. If you need performance optimization, session management or caching integrations, please .

Source Code:

Support Plans:

Bug Tracker:

BoxLang ORM module
Hibernate ORM
sponsoring a feature or opening a support contract
BoxLang
contact us for support
github.com/ortus-boxlang/bx-orm
https://www.ortussolutions.com/services/support
https://ortussolutions.atlassian.net/browse/BLMODULES

Installation

Get up and running in seconds!

CommandBox

If you're using CommandBox to manage your BoxLang server, it's as easy as running install bx-orm:

box install bx-orm

You may need to install bx-compat-cfml as well for backwards-compatible ORM behaviors:

box install bx-orm bx-compat-cfml

install-bx-module

For miniserver usage outside of CommandBox, use the install-bx-module CLI command:

install-bx-module bx-orm

Note that bx-orm currently only supports the web runtime.

About This Book

More info on this documentation gitbook for bx-orm

The source code for this book is hosted in GitHub:

  • The majority of code examples in this book are done in cfscript.

Notice of Liability

The information in this book is distributed “as is”, without warranty. The author and Ortus Solutions, Corp shall not have any liability to any person or entity with respect to loss or damage caused or alleged to be caused directly or indirectly by the content of this training book, software and resources described in it.

Contributing

Charitable Proceeds

Shalom Children's Home

Shalom Children’s Home is one of the ministries that is dear to our hearts located in El Salvador. During the 12 year civil war that ended in 1990, many children were left orphaned or abandoned by parents who fled El Salvador. The Benners saw the need to help these children and received 13 children in 1982. Little by little, more children came on their own, churches and the government brought children to them for care, and the Shalom Children’s Home was founded.

Shalom now cares for over 80 children in El Salvador, from newborns to 18 years old. They receive shelter, clothing, food, medical care, education and life skills training in a Christian environment. The home is supported by a child sponsorship program.

We have personally supported Shalom for over 6 years now; it is a place of blessing for many children in El Salvador that either have no families or have been abandoned. This is good earth to seed and plant.

Configuration

Easily configure Hibernate with BL

Application.bx

The ORM can be configured by a struct of settings set in this.ormSettings in your main Application.bx:

ORM Settings

The full list of available properties you can use to configure the ORM are the following:

Dialects

By using the ormsettings.dialect you can tell Hibernate which specific database dialect to use for building queries. By default, Hibernate tries to inspect the datasource and define it for you. 95% of the time, this works. However, if you want a specific one, then you can use the following names or a fully qualified Java class name.

Sample Config

Here is an example configuration from the popular ContentBox Modular CMS application

Custom Naming Strategy

You can define your own naming convention for table and column names by pointing this.ormSettings.namingStrategy to a custom boxlang class:

The UnderscoreNamingStrategy.bx class should then define two methods: getTableName() and getColumnName():

Release History

Release history for all bx-orm versions

In this section, you will find the release notes for each version we release under this major version. If you are looking for the release notes of previous major versions, use the version switcher at the top left of this documentation book. Here is a breakdown of our major version releases.

v1.x

1.x

Version 1.x release notes for the BoxLang ORM Module

1.0.11 - 2025-06-10

🐛 Fixed

1.0.10 - 2025-05-03

🐛 Fixed

⭐ Added

1.0.9 - 2025-04-29

🐛 Fixed

1.0.8 - 2025-04-25

⭐ Added

🐛 Fixed

1.0.7 - 2025-04-14

🐛 Fixed

  • Fix string casting error on lazy property annotation

1.0.6 - 2025-04-14

🐛 Fixed

⭐ Added

1.0.5 - 2025-04-07

🐛 Fixed

  • Removed debugging code

1.0.4 - 2025-04-06

🐛 Fixed

1.0.3 - 2025-04-06

🐛 Fixed

1.0.2 - 2025-04-04

No significant changes.

1.0.1 - 2025-04-04

⭐ Added

🐛 Fixed

1.0.0 - 2025-03-26

  • First iteration of this module

You can freely contribute to it and submit pull requests. The contents of this book is copyright by and cannot be altered or reproduced without author's consent. All content is provided "As-Is" and can be freely distributed.

The majority of code generation and running of examples are done via CommandBox: The ColdFusion (CFML) CLI, Package Manager, REPL - ​

We highly encourage contribution to this book and our open source software. The source code for this book can be found in our where you can submit pull requests.

10% of the proceeds of this book will go to charity to support orphaned kids in El Salvador - . So please donate and purchase the printed version of this book, every book sold can help a child for almost 2 months.

Setting Name
Default
Description
Dialect (short name)
Remarks

See the Hibernate Dialect Section:

Check out our for the latest updates and changes.

Fixed issue with default cache not being created when cache provider was empty - Resolves

Fix error starting up on non-ORM apps - Resolves

Add support for tinyint and tinyinteger ORM types - Resolves

Skip type conversion on version properties - Resolves

Drop ormApp instantiation in baseORMBIF - Fixes

Improve default datasource look up and throw error if empty - See

See .

Throw or log an error when class annotation on association is an empty string - Resolves

Fix support for dataType annotation on version properties - Resolves

Implement 'index' annotation - Resolves

Implement multi-column support in column and fkcolumn - Resolves

Implement cache support at the property level - Resolves

See .

Implement elementType,elementColumn annotations - Resolves

Fixes for map collection when structkeytype or structkeycolumn are ignored - Resolves

Skip usage of AttributeConverter on identifier properties - Resolves

See .

Set hibernate version in build so ORMGetHibernateVersion() stays accurate - See

Foreign key must have same number of columns as the referenced primary key - Resolves

Missing FKColumn on To-Many Relationship Should Check the Inverse Relationship for Column data - Resolves

XMLWriter - Skip id,composite-id XML rendering on subclasses - Resolves

XML Writer - Skip generator on composite keys - Resolves

XMLWriter - Don't set insert or update on one-to-one elements - Resolves

Fix support for 'params' attribute string notation - See

See .

See .

Fixed support for custom naming strategies - See

Fixed "smart" naming strategy when entity name begins with an uppercase character - See

Move compat configuration to bx-compat-cfml - See

Fixed the two types of discriminator generation order - See

fix bag element being appended to wrong node on subclasses - See

change to use caster so that lazy=true does not error - See

Add missing date property type - See

Add alternate spellings for big decimal and big integer - See

Add flush after commit on transaction end - See

See .

See .

Metadata parsing throws error on empty class despite skipCFCWithError setting - Resolves

See .

EntityLoad returning incorrect results with criteria struct filter on parent properties - Resolves

Hibernate Criteria Querys using get are returning proxies instead of the entity - Resolves

ensure proxies in session are expanded when a load is requested - See

Error on first ORM request after Application Timeout - Resolves

BoxProxy Struct Implementation causes validation exceptions - Resolves

See .

See .

Allow options as third arg to ORMExecuteQuery - See

Add handling for not null on to-one relationship - See

Attempt casting uniqueOrOrder to string in EntityLoad BIF - See

Ignore null uniqueOrOrder argument in EntityLoad BIF - See

Fix chicken/egg issues with app startup by lazy-initializing the EventHandler - See

WrongClassException when re-querying for the same object in a session - Resolves

Disable not-null annotation usage on one-to-one relationships - See

fix explicit nulls on setters - See

Auto-generated has methods are overriding declared methods in ORM entities - Resolves

x-to-one generated hasX() methods are not returning the correct values - Resolves

See .

See

Ortus Solutions, Corp
https://www.ortussolutions.com/products/commandbox
GitHub repository
https://www.harvesting.org/
class{
    this.ORMenabled = true;
    this.ormSettings = {
        // << Here Be ORM Configuration! 🤪 >>
    };
}

Cache71

Support for the Caché database, version 2007.1.

CockroachDB192

Support for the CockroachDB database version 19.2.

CockroachDB201

Support for the CockroachDB database version 20.1.

CUBRID

Support for the CUBRID database, version 8.3. May work with later versions.

DB2

Support for the DB2 database, version 8.2.

DB297

Support for the DB2 database, version 9.7.

DB2390

Support for DB2 Universal Database for OS/390, also known as DB2/390.

DB2400

Support for DB2 Universal Database for iSeries, also known as DB2/400.

DB2400V7R3

Support for DB2 Universal Database for i, also known as DB2/400, version 7.3

DerbyTenFive

Support for the Derby database, version 10.5

DerbyTenSix

Support for the Derby database, version 10.6

DerbyTenSeven

Support for the Derby database, version 10.7

Firebird

Support for the Firebird database

FrontBase

Support for the Frontbase database

H2

Support for the H2 database

HANACloudColumnStore

Support for the SAP HANA Cloud database column store.

HANAColumnStore

Support for the SAP HANA database column store, version 2.x. This is the recommended dialect for the SAP HANA database. May work with SAP HANA, version 1.x

HANARowStore

Support for the SAP HANA database row store, version 2.x. May work with SAP HANA, version 1.x

HSQL

Support for the HSQL (HyperSQL) database

Informix

Support for the Informix database

Ingres

Support for the Ingres database, version 9.2

Ingres9

Support for the Ingres database, version 9.3. May work with newer versions

Ingres10

Support for the Ingres database, version 10. May work with newer versions

Interbase

Support for the Interbase database.

JDataStore

Support for the JDataStore database

McKoi

Support for the McKoi database

Mimer

Support for the Mimer database, version 9.2.1. May work with newer versions

MySQL5

Support for the MySQL database, version 5.x

MySQL5InnoDB

Support for the MySQL database, version 5.x preferring the InnoDB storage engine when exporting tables.

MySQL57InnoDB

Support for the MySQL database, version 5.7 preferring the InnoDB storage engine when exporting tables. May work with newer versions

MariaDB

Support for the MariaDB database. May work with newer versions

MariaDB53

Support for the MariaDB database, version 5.3 and newer.

Oracle8i

Support for the Oracle database, version 8i

Oracle9i

Support for the Oracle database, version 9i

Oracle10g

Support for the Oracle database, version 10g

Pointbase

Support for the Pointbase database

PostgresPlus

Support for the Postgres Plus database

PostgreSQL81

Support for the PostgrSQL database, version 8.1

PostgreSQL82

Support for the PostgreSQL database, version 8.2

PostgreSQL9

Support for the PostgreSQL database, version 9. May work with later versions.

Progress

Support for the Progress database, version 9.1C. May work with newer versions.

SAPDB

Support for the SAPDB/MAXDB database.

SQLServer

Support for the SQL Server 2000 database

SQLServer2005

Support for the SQL Server 2005 database

SQLServer2008

Support for the SQL Server 2008 database

Sybase11

Support for the Sybase database, up to version 11.9.2

SybaseAnywhere

Support for the Sybase Anywhere database

SybaseASE15

Support for the Sybase Adaptive Server Enterprise database, version 15

SybaseASE157

Support for the Sybase Adaptive Server Enterprise database, version 15.7. May work with newer versions.

Teradata

Support for the Teradata database

TimesTen

Support for the TimesTen database, version 5.1. May work with newer versions

// THE CONTENTBOX DATASOURCE NAME
this.datasource  = "contentbox";
// ORM SETTINGS
this.ormEnabled  = true;
// cfformat-ignore-start
this.ormSettings = {
	// ENTITY LOCATIONS, ADD MORE LOCATIONS AS YOU SEE FIT
	entityPaths           : [
		// If you create your own app entities
		"models",
		// The ContentBox Core Entities
		"modules/contentbox/models",
		// Custom Module Entities
		"modules_app",
		// Custom Module User Entities
		"modules/contentbox/modules_user"
	],
	// THE DIALECT OF YOUR DATABASE OR LET HIBERNATE FIGURE IT OUT, UP TO YOU TO CONFIGURE.
	dialect              : request.$systemHelper.getSystemSetting( "ORM_DIALECT", "" ),
	// DO NOT REMOVE THE FOLLOWING LINE OR AUTO-UPDATES MIGHT FAIL.
	dbcreate             : "update",
	secondarycacheenabled: request.$systemHelper.getSystemSetting( "ORM_SECONDARY_CACHE", false ),
	cacheprovider        : request.$systemHelper.getSystemSetting( "ORM_SECONDARY_CACHE", "ehCache" ),
	logSQL               : request.$systemHelper.getSystemSetting( "ORM_LOGSQL", false ),
	sqlScript            : request.$systemHelper.getSystemSetting( "ORM_SQL_SCRIPT", "" ),
	flushAtRequestEnd    : false,
	autoManageSession    : false,
	eventHandling        : true,
	eventHandler         : "cborm.models.EventHandler",
	ignoreParseErrors     : true,
	// TURN ON FOR Debugging if ORM mappings are not working.
	savemapping          : false
};
this.ormSettings = {
	// ...
	namingStrategy : "models.orm.UnderscoreNamingStrategy"
}
// models/orm/UnderscoreNamingStrategy.bx
class {
	function getTableName( string tableName ){
		// funky table name conversion here...
	}

	function getColumnName( string columnName ){
		// funky column name conversion here...
	}
}
Hibernate_User_Guide.html#database-dialect
1.x release notes
BLMODULES-53
BLMODULES-49
BLMODULES-59
BLMODULES-45
BLMODULES-54
BLMODULES-56
v1.0.11 commit history on github
BLMODULES-50
BLMODULES-51
BLMODULES-47
BLMODULES-48
BLMODULES-52
v1.0.10 commit history on github
BLMODULES-46
BLMODULES-45
BLMODULES-44
v1.0.9 commit history on github
a8c7c16
BLMODULES-41
BLMODULES-42
BLMODULES-38
BLMODULES-40
BLMODULES-39
BLMODULES-40
v1.0.8 commit history on github
v1.0.7 commit history on github
8e68206
b47b512
c8b7173
ea62a62
f82b2ac
0096387
c6ec8a2
5e199f9
e2df378
v1.0.6 commit history on github
v1.0.5 commit history on github
BLMODULES-37
v1.0.4 commit history on github
BLMODULES-36
BLMODULES-35
5b07e2c
BLMODULES-30
BLMODULES-33
v1.0.3 commit history on github
v1.0.2 commit history on github
b5efc84
6792fb0
98f6734
394d9ba
699f15b
BLMODULES-12
c512848
819fffb
BLMODULES-31
BLMODULES-32
v1.0.1 commit history on github
v1.0.0 commit history on github

autoGenMap

true

Specifies whether ColdFusion should automatically generate entity mappings for the persistent classes. If autogenmap=false, the mapping should be provided in the form of .HBMXML files.

autoManageSession

true

cacheConfig

true

cacheProvider

"ehcache"

Specifies the cache provider that ORM should use as a secondary cache. The values can be:

  • Ehcache

  • ConcurrentHashMap

  • The fully qualified name of the class for any other cache provider.

catalog

Specifies the default Database Catalog that ORM should use.

entityPaths

empty

Specifies the directory (or array of directories) that should be used to search for persistent CFCs to generate the mapping.

Always specify it or pay a performance startup price.

Important:

If it is not set, the extension looks at the application directory, its sub-directories, and its mapped directories to search for persistent CFCs.

datasource

application.datasource

This setting defines the data source to be utilized by the ORM. If not used, defaults to the this.datasource in the Application.bx

dbcreate

none

  • update : Creates the database according to your ORM model. It only does incremental updates. It will never remove tables, indexes, etc.

  • dropcreate : Same as above but it destroys the database if it has ny content and recreates it every time the ORM is reloaded.

  • none : Does not change the database at all.

dialect

autodiscover

eventHandling

false

If true, then it enables the ORM event callbacks in entities and globally via the eventHandler

eventHandler

Path to the .bx class that will manage the global ORM events.

flushAtRequestEnd

true

Specifies if an orm flush should be called automatically at the end of a request. In our opinion this SHOULD never be true. A database persistence should be done via transaction tags and good transaction demarcation.

logSQL

false

Specifies if the SQL queries should be logged to the console.

namingstrategy

default

ormconfig

savemapping

false

If enabled, the ORM will create the Hibernate mapping XML (*.hbmxml) files alongside the entities. This is great for debugging your entities and relationships.

schema

The default database schema to use

secondaryCacheEnabled

false

ignoreParseErrors

false

If true, then the ORM will ignore classes that have compile time errors in them. Use false to throw exceptions.

sqlScript

Path to a SQL script file that will be executed after the ORM is initialized. A great way to seed a database.

useDBForMapping

true

Specifies whether the database has to be inspected to identify the missing information required to generate the Hibernate mapping.

The database is inspected to get the column data type, primary key and foreign key information.

Custom Hibernate Config

For full Hibernate configuration support, you can create an XML file containing any configuration properties you wish to configure:

You can then populate the XML file with valid Hibernate configuration syntax:

Allows the engine to manage the Hibernate session. It is recommended not to let the engine manage it for you. Use transaction blocks in order to demarcate your regions that should start, flush and end a transaction.

Specifies the location of the configuration file that the secondary cache provider should use. This setting is used only when secondaryCacheEnabled=true. See below.

See below.

The dialect to use for your database. By default Hibernate will introspect the datasource and try to figure it out. See the dialects section below. You can also use the fully Java qualified name of the class. See the section below.

Defines the naming convention to use on table and column names. - default : Uses the table or column names as is - smart : This strategy changes the logical table or column name to uppercase. - CFC PATH : Use your own CFC to determine naming - see .

The path to a custom Hibernate configuration file: - hibernate.properties - hibernate.bx.xml Please see

Enable the secondary cache or not. See our section.

https://docs.jboss.org/hibernate/orm/5.4/userguide/html_single/Hibernate_User_Guide.html#transactions
Secondary Cache
Secondary Cache
dialects
Custom Naming Strategy
Custom Hibernate Config
Caching
this.ormSettings = {
    // ...
    ormconfig : "./config/persistence.xml"
};
<!-- persistence.xml -->
<?xml version="1.0" encoding="UTF-8"?>    
<!DOCTYPE hibernate-configuration PUBLIC    
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"    
        "https://hibernate.org/dtd/hibernate-reverse-engineering-3.0.dtd">    
<hibernate-configuration>    
    <session-factory>    
    
    <!-- https://docs.jboss.org/hibernate/orm/5.4/javadocs/org/hibernate/cfg/AvailableSettings.html#USE_SQL_COMMENTS -->
    <property name="hibernate.use_sql_comments">true</property>
    <property name="hibernate.cache.use_query_cache">true</property>
         
    </session-factory>
</hibernate-configuration>

Logging

How do Hibernate logs work in bx-orm?

There are several categories of logs generated during normal use of a bx-orm application:

  1. bx-orm logs

  2. SQL logs

  3. Hibernate logs

bx-orm logs

Logging statements generated from bx-orm itself will be output to the orm.log file located in the boxlang runtime logs/ directory.

This log file may look something like the below when DEBUG mode is enabled:

[2025-04-25T09:50:34,965] [Test worker] [DEBUG] [ORM] beforeApplicationListenerLoad fired; checking for ORM configuration 
[2025-04-25T09:50:34,972] [Test worker] [DEBUG] [ORM] ORMEnabled, starting up ORM app for [myApp] 
[2025-04-25T09:50:34,979] [Test worker] [DEBUG] [ORM] ORMApp created for application: [myapp_1428735748] 
[2025-04-25T09:50:35,001] [Test worker] [DEBUG] [ORM] Found more than 20 entities; parallelizing metadata introspection 
[2025-04-25T09:50:35,006] [Test worker] [DEBUG] [ORM] Loading metadata for class /app/models/cms/Author.bx 
[2025-04-25T09:50:35,007] [Test worker] [DEBUG] [ORM] Parsing class file: [/app/models/cms/Author.bx] 
...

SQL Logs

bx-orm has the ability to log every SQL statement generated from ORM code. For example, firing entityDelete( myEntity ) will generate a DELETE SQL statement for deleting the entity (table row) in question from the entity table.

A quick example might be this log, generated after firing entityNew( "Manufacturer", properties ):

[2025-04-25T09:50:46,264] [Test worker] [DEBUG] [org.hibernate.SQL] 
    /* insert Manufacturer
        */ insert 
        into
            manufacturers
            (name, address, id) 
        values
            (?, ?, ?) 

To enable this behavior, set this.ormSettings.logSQL to true in your Application.bx:

this.ormSettings={
	"logSQL" : "true"
	// ...
}

These SQL statements will also log to the orm.log file located in ${boxlang-home}/logs.

Hibernate-native logs

Hibernate-native logging statements will also be captured in the orm.log file located in ${boxlang-home}/logs.

Identifiers

All about entity identifiers, from primary keys, and generators to composite keys and field types.

Identifier properties are denoted via fieldtype="id".

We highly recommend disabling updates on identifier properties via update="false":

property name="id"
            fieldtype="id"
            ormtype="string"
            generator="assigned"
            update="false";

Common Generator Types

Assigned Generator

The Assigned generator is the default identifier generator type, and simply allows the application (your BL) to assign identifier values prior to insertion. You can think of this as generator=none.

property name="id"
            fieldtype="id"
            generator="assigned"
            update="false";
function preInsert( entity ){
    setId( createUUID() );
}

Select Generator

A select generator will attempt to select the next identifier value from the specified selectKey column:

property name="userID"
            fieldtype="id"
            generator="select"
            selectKey="ssn"
            update="false";

UUID Generator

The UUID generator uses Hibernate's uuid generator under the hood:

property name="userID"
            fieldtype="id"
            generator="uuid"
            update="false";

Increment Generator

The Increment generator uses a simple incrementing value to create identifiers. Do not use in concurrent applications, as the values may no longer be unique.

property name="userID"
            fieldtype="id"
            generator="increment"
            update="false";

Other Valid Generator Types

There are several lesser-known identifier generator types, including:

  • foreign - use a specific property from a foreign entity

  • seqhilo

  • sequence

  • select - select the next value from the column denoted in selectKey

  • uuid - use Hibernate's UUID generation

For more information on configuring loggers, see the documentation.

lets the application assign an identifier to the object before save() is called. This is the default strategy if no element is specified. -

Assigned generators will commonly use to assign the identifer value:

retrieves a primary key, assigned by a database trigger, by selecting the row by some unique key and retrieving the primary key value. -

uses a 128-bit UUID algorithm to generate identifiers of type string that are unique within a network (the IP address is used). The UUID is encoded as a string of 32 hexadecimal digits in length. -

Generates identifiers of type long, short or int that are unique only when no other process is inserting data into the same table. Do not use in a cluster. -

Boxlang Logging
Hibernate 3.3 mapping reference docs
a preInsert() event listener
Hibernate 3.3 mapping reference docs
Hibernate 3.3 mapping reference docs
Hibernate 3.3 mapping reference docs

Relationships

Entity relationships let you define an association between two entity types.

Every relationship property must define the state of the relationship. In each case, the relationship property is defined in an entity which represents the "left" side of the relationship. If you bring a Posts relationship into the User entity, then from the User entity, the User is the left side of the relationship, and Posts is the right.

One To One

A one to one relationship couples a single row on the left side to a single row on the right side:

property name="Contact"
    fieldtype="one-to-one"
    class="Contact";

One to one relationships can be seen as simply extending the entity with additional information. Since there is no possibility of multiple records per entity instance, it may be worthwhile to set lazy=false to fetch the related entity along with any entity load:

property name="Contact"
    fieldtype="one-to-one"
    class="Contact"
    lazy="false";

One To Many

A one to many relationship couples a single row on the left side (the "one") to multiple rows on the right side (the "many"):

class entityName="User" persistent="true"{
    property name="posts"
        fieldtype="one-to-many"
        class="Post";
}

You'll normally want to set lazy="true" to (for example) avoid fetching every Post on a User:

property name="posts"
    fieldtype="one-to-many"
    class="Post"
    lazy="true";

Many To One

A many to one relationship couples multiple rows on the left side (the "many") to a single row on the right side( the "one"):

class entityName="Post" persistent="true"{
    property name="Authors"
        fieldtype="many-to-one"
        class="User";
}

Thus, a single Post can have only one Author... but an author (or a User, really) can have many Posts.

Many To Many

A many to many relationship allows each entity to relate to multiple rows on the opposite side. A good example might be a blog which allows multiple authors for a single blog post. Each blog post can then have multiple authors, and each author has (likely) written multiple blog posts:

class entityName="User" persistent="true"{
    property name="posts"
        fieldtype="many-to-many"
        class="Post"
        linktable="user_posts_link";
}

The linktable attribute is required on a many-to-many property to set the locationfor storing join records. You can further alter the storage location via linkschema and linkcatalog:

property name="posts"
    fieldtype="many-to-many"
    class="Post";
    linkschema="blog"
    linkcatalog="dbo";

Singular Name

On many* relationships like one-to-many, many-to-one, etc., you'll be manipulating the full set of items via the property name: hasAuthors(), setAuthors(), etc. However, this plural terminology becomes weird when used on a single item addition or removal, such as addAuthors( Author ). For this reason, you can define a singularName=STRING attribute to clean up your entity manipulation:

property name="Authors"
    singularName="Author"
    fieldtype="many-to-one"
    class="User";

Lazy

Man, you wanna get lazy? How about don't-fetch-the-data-until-you-need-it kinda lazy?

Using lazy=true, we can tell Hibernate not to fetch the relational data unless and until a method call such as Authors() attempts to load it. This greatly improves performance on page requests which do not need that particular data:

property name="posts"
    fieldtype="one-to-many"
    class="Post"
    lazy="true";

We can also use lazy=extra to only retrieve the rows that we touch. This may work well if we commonly only access a few rows out of the full set of child items:

property name="posts"
    fieldtype="one-to-many"
    class="Post"
    lazy="extra";

Relationship Methods

This section is missing documentation - would you care to ?

add it yourself

Properties

Entity properties are how we map table columns to boxlang object values. You can specify an entity property by setting persistent="true" on any property inside a persistent boxlang class:

class persistent="true"{
    property name="name" type="string" persistent="true";
}

By default, all properties inside a persistent=true class are assumed to be persistent as well. Thus, we can skip the persistent=true annotation for brevity:

class persistent="true"{
    property name="name" type="string";
}

Common Property Annotations

Attribute
Type
Description

persistent

boolean

Define this property as a persistent property. If false, this property will be completely ignored from an orm standpoint.

name

string

Property name

default

string

Default value for the property. This only reaches the boxlang engine, and does not affect creation of the entity table.

column

string

Table column where the property value is stored.

dbDefault

string

Set the default value for the property.

Make sure you quote datetime dbdefault values to avoid invalid date errors in MySQL:

property
    name     ="createdOn"
    ormtype  ="datetime"
    dbdefault="'2016-10-10'";

Property Types

There are several "type" concepts and annotations you may need to use to keep the proper format when persisting or retrieving table data. While these may look similar, they are not equivalent.

Attribute
Examples
Description

type

date,numeric

Boxlang data type

fieldtype

column,id, one-to-many

Denote a special type of field, like an identifier or relationship field.

ormType

big_decimal,timestamp

Data type for the database value.

sqlType

nvarchar

A vendor-specific SQL type used for table creation only. This can normally be ignored.

Field Type

The fieldtype attribute allows you to define the behavior and purpose of this property:

property
    name="userID"
    fieldtype="id"
    type="string";

There are several options for the fieldtype value:

  • column - By far the most common, this is the default behavior of every field.

  • id - Notes this field as the primary key or part of the a composite key.

  • collection - Denote a collection of items - this could represent a struct, an array

  • timestamp - Denote a timestamp field

  • primary - Not currently used.

Generator Annotations

Attribute
Type
Description

generator

string

One of increment,identity,native,seqhilo,uuid,guid,select,foreign, assigned

params

struct, string

{ "table: "uuid_table", column: "uuid_value_column" }

sequence

string

selectkey

string

Only used with generator=select. Specify the select key to use when selecting sequence values from the database.

generated

string

always, insert, never.

Validation

Attribute
Type
Description

insert

boolean

Allow inserting values to new rows.

update

boolean

Allow value updates on existing rows.

notnull

boolean

Specify a not-null constraint.

uniquekey

string

Specify a key name for a unique constraint. Useful for defining a unique constraint across multiple columns.

unique

boolean

Specify a unique constraint. Default false.

validateParams

string

Not currently supported

validate

string

Not currently supported

Collection Modifiers

These property annotations are used when setting fieldtype="collection" and collectiontype is either struct or map.

Attribute
Type
Description

structkeycolumn

string

structkeytype

string

elementtype

string

elementcolumn

string

Relationship Modifiers

Attribute
Type
Description

table

string

Define the table where the foreign items are stored.

lazy

boolean, string

Define a lazy association retrieval type. One of true, false, extra.

inverse

boolean

Specify that the association "owner" is referenced and managed on the opposite entity - not this current entity.

inversejoincolumn

string

Specify the join column on the associated entity. For inverse associations only.

linkschema

string

Specify the schema name of the link table

linkcatalog

string

Specify the catalog name of the link table

linktable

string

Specify the name of the link table

missingRowIgnored

boolean

Do not throw an error if a foreign key has no match in the foreign entity

fkcolumn

string

orderby

string

fetch

string

cascade

string

constrained

boolean

optimisticLock

boolean

Enable optimistic locking on this association. One of all, dirty, version, none.

mappedby

string

Specify the property on the association that maps to this entity.

class

string

Specify the location of the foreign entity.

joinColumn

string

Join the foreign entity on this column in this entity.

where

string

Arbitrary SQL where clause for the relation.

singularname

Not currently supported

Other

Attribute
Type
Description

scale

integer

length

integer

precision

integer

formula

string

Define this property as a computed property by using a SQL query to determine the property value. Formula properties cannot be modified.

index

string

Key name for a property value index.

cacheUse

string

Define a cache type to use for this property. One of read-only, nonstrict-read-write, read-write, or transactional.

cacheName

string

Set the name of the cache to use for this property.

unSavedValue

string

Set a value to use for newly instantiated objects.

Formula Property

property name="totalPosts"
    ormType="integer"
    formula="(
        SELECT COUNT(*)
        FROM posts
        WHERE posts.FK_user = id
    )";

Unsupported Attributes

Querying

version - Denote a version field, useful for on an entity

one-to-one - Denote a

one-to-many - Denote a

many-to-one - Denote a

many-to-many - Denote a

Only valid for one-to-one relationships.

Looking for better support of a specific persistent attribute? .

This page is missing documentation - would you care to ?

optimistic locking
one-to-one relationship
one-to-many relationship
many-to-one relationship
many-to-many relationship
Contact our Support team to consider sponsoring this feature
add it yourself

Entities

Learn the basics of modeling ORM entities

A persistent entity is a boxlang class that is marked as a database entity via the persistent annotation upon the class definition:

class persistent="true"{

}

By default, the entity name will be the boxlang class file name - minus the file extension, of course. We can modify the entity name via the entityname annotation:

class persistent="true" entityname="Author" {

}

And the table name via the table annotation:

class persistent="true" entityname="Author" table="authors" {

}

Here's the full list of available annotations for a persistent class:

Attribute
Type
Default
Description

persistent

boolean

false

Mark this class as an ORM entity

entityname

string

Set a custom entity name which is different than the boxlang class name

table

string

Specify the database table name

schema

string

Specify the database schema name.

catalog

string

Specify the database catalog name.

dynamicinsert

Specifies whether INSERT SQL is to be generated at runtime. Only those columns whose values are not null are included in the SQL.

dynamicinsert

boolean

false

Specifies whether INSERT SQL is to be generated at runtime. Only those columns whose values are not null are included in the SQL.

dynamicupdate

boolean

false

Specifies whether UPDATE SQL is to be generated at runtime. Only those columns whose values are not null are included in the SQL.

readonly

boolean

false

Specify whether table is readonly or not

selectbeforeupdate

boolean

Specify whether Hibernate should never perform an SQL UPDATE unless it is certain that an object is actually modified. In cases when a transient object is associated with a new session using update(), Hibernate performs an extra SQL SELECT to determine if an UPDATE is actually required.

optimisticlock

string

Determines the locking strategy. It can be any one of:all,dirty,version,none

batchsize

integer

An integer value that specifies the number of records to be retrieved at a single instance.

lazy

boolean

true

Whether loading is to be done lazily or not.

rowid

string

Specify the row id

discriminatorColumn

string

Use this attribute to define the discriminator column to be used in inheritance mapping

discriminatorValue

string

Use this attribute to define the discriminator value to be used in inheritance mapping

joinColumn

string

Define a join column for inheritance mapping

embedded

boolean

Marks class as embedded, used when a class has an embedded object which also needs to be persisted along with the parent's data

cacheUse

string

Specify the caching strategy to be used for caching this entity's data in the secondary cache:read-only

cacheName

string

Specify the name of the secondary cache

saveMapping

boolean

false

Specifies whether the generated Hibernate mapping file has to be saved to disk. If you set the value to true, the Hibernate mapping XML file is saved as {class name}.hbm.xml in the same directory as the boxlang class.

datasource

string

Name a specific datasource to persist this entity to.

See Hibernate 3.3 Mapping Documentation

Session Management

Secondary Caches

Hibernate's secondary cache is a powerful tool that can greatly improve the performance of your application. By storing frequently accessed data in memory, the secondary cache can reduce the number of database queries that need to be made, resulting in faster response times and more efficient use of system resources. Whether you're working on a small project or a large enterprise application, the secondary cache is an essential part of any Hibernate-based system. So if you want to get the most out of your Hibernate application, take advantage of this powerful caching feature!

Configuration

A secondary cache provider is a class that manages a level of caching secondary to Hibernate's main caching context - the Hibernate session. A secondary cache enables longer-running cache contexts, more fine-grained control over cache busting, and other performance-related benefits.

The only setting necessary to enable secondary caching is the secondaryCacheEnabled setting:

this.ormSettings = {
    secondaryCacheEnabled : true
};

To configure the caching, specify the path to an XML cache configuration file in cacheConfig:

this.ormSettings = {
    secondaryCacheEnabled: true,
    cacheConfig          : "./config/ehcache.xml"
};

This ehcache.xml cache configuration then should look something like this:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true" name="default">
    <diskStore path="java.io.tmpdir"/>
        <defaultCache
            maxElementsInMemory="10000" eternal="false"
            timeToIdleSeconds="120" timeToLiveSeconds="120"
            maxElementsOnDisk="10000000" diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
            <persistence strategy="localTempSwap"/>
        </defaultCache>
        <cache
            name="Autos"
            maxElementsInMemory="20"
            overflowToDisk="false"
            eternal="true">
        </cache>
</ehcache>

Alternate Cache Providers Are Unsupported

While there is a cacheProvider setting, only EHCache (currently) is supported as a secondary cache provider.

this.ormSettings = {
    secondaryCacheEnabled : true,
    // NOT SUPPORTED!
    cacheProvider : "ConcurrentHashMap"
};

Thus, any usage of cacheProvider other than "ehcache" will be ignored.

Savepoints are not currently supported on ORM transactions.

HQL

Built-In Functions

bx-orm implements a number of built-in-functions (BIFs) for loading and manipulating entities as well as managing the ORM session:

EntityDelete

EntityDelete allows you to delete the row associated with an instantiated entity from the database:

Only a single argument is accepted - the entity to delete - and the deletion is not persisted until the session is flushed.

Returns: null

EntityLoad

Returns: Array|Class|null

EntityLoadByExample

Returns: Array|Class|null

EntityLoadByPK

EntityLoadByPK() allows you to instantiate an entity using the row identified by a primary key:

Returns: Class|null

EntityMerge

EntityMerge() will merge a "detached" entity (meaning, not connected to any open session) back into the session.

For example, running ormClearSession() will detach all loaded entities from the session. If you then make changes to an entity via a setter and run ormFlush(), those entity modifications will not be persisted unless you first merge the entity back to the session:

Returns: Class

EntityNameArray

EntityNameArray() returns an array of all mapped entity names for the boxlang application:

EntityNameArray accepts no arguments.

Returns: Array

EntityNameList

True to its name, EntityNameList returns a string list of all mapped entity names for the boxlang application:

You can pass a string delimiter value as the first argument, if you don't like commas:

Returns: string

EntityNew

The entityNew() method allows you to create a new instance of a known entity type:

You can also pass a struct of properties to populate into the entity:

Note that if you try to populate a property which does not exist, you will get an error:

This will throw an error: class [Auto] has no function with name [setPROPTHATDOESNTEXIST]

Returns: Class

EntityReload

entityReload() will reload or refresh the entity state from the database. Local, unpersisted modifications will be replaced with database values.

Here's a quick example:

Returns: null

EntitySave

EntitySave() is how you save entity modifications. The changes will not persist to the database until ormFlush() is called:

EntitySave accepts an optional boolean parameter, forceInsert, which will tell Hibernate to skip the entity existence check and insert the entity:

Most of the time this will be unnecessary.

Returns: null

EntityToQuery

Returns: Query

IsValidDatasource

Returns: Boolean

ORMClearSession

Returns: null

ORMCloseAllSessions

Returns: null

ORMCloseSession

Returns: null

ORMEvictCollection

Returns: null

ORMEvictEntity

Returns: null

ORMEvictQueries

Returns: null

ORMExecuteQuery

Returns: Array|Struct|any

ORMFlush

Returns: null

ORMGetSession

Returns: Session

ORMGetSessionFactory

Returns: SessionFactory

ORMQueryExecute

Alias for ORMExecuteQuery().

Returns: Array|Struct|any

ORMReload

Returns: null

This page is missing documentation - would you care to ?

Please see the for all the wonderful caching strategies you can do with Hibernate.

Looking for alternate cache providers? .

This page is missing documentation - would you care to ?

add it yourself
caching section
Contact our Support team to consider sponsoring this feature
entityDelete( myEntity );
entityDelete( myEntity );
// entity (row) still exists in the database.
ormFlush();
// entity (row) is now wiped from the database.
var theUser = entityLoadByPk( "User", url.userID );
var detachedAutoEntity = entityLoadByPK( "Auto", "12345" );

// make a change but don't save it
detachedAutoEntity.setModel( "Fusion" );

// clear session - will "detach" the entity
ormClearSession();

// "merge" it back to the session
var merged = entityMerge( detachedAutoEntity );

// changes should be reflected in the new entity
expect( merged.getModel() ).toBe( "Fusion" );
var entityTypes = entityNameArray();
var entityTypes = entityNameList();
var entityTypes = entityNameList( "|" );
var myCar = entityNew( "Auto" );
var myCar = entityNew( "Auto", {
  make : "Ford",
  model : "Fusion",
  id : createUUID()
} );
var myCar = entityNew( "Auto", {
    make : "Ford",
    model : "Fusion",
    propThatDoesntExist : "abc"
} );
var myCar = entityLoadByPK( "Auto", "12345" );

// make a change but don't save it
myCar.setModel( "Revuelto" );

// reload the entity
entityReload( myCar );

// our local changes should be replaced with the DB value
expect( myCar.getModel() ).toBe( "Aventador" );
var myCar = entityNew( "Auto", {
  make : "Ford",
  model : "Fusion",
  id : createUUID()
} );
entitySave( myCar );
ormFlush();
var myCar = entityNew( "User", {
  username : "Johnny.Appleseed",
  password : "McinT0sh"
} );
entitySave( myCar, true );
add it yourself
EntityDelete
EntityLoad
EntityLoadByExample
EntityLoadByPK
EntityMerge
EntityNameArray
EntityNameList
EntityNew
EntityReload
EntitySave
EntityToQuery
IsValidDatasource
ORMClearSession
ORMCloseAllSessions
ORMCloseSession
ORMEvictCollection
ORMEvictEntity
ORMEvictQueries
ORMExecuteQuery
ORMFlush
ORMGetSession
ORMGetSessionFactory
ORMQueryExecute
ORMReload

Events

Easily run actions on entity insertion, update, and more with event listeners

Hibernate ORM allows reacting to various events in the session lifecycle such as onPreInsert, onPostUpdate, onFlush, etc. You can enable event handling in bx-orm by setting eventHandling to true in your this.ormSettings struct:

this.ormSettings = {
    eventHandling: true
};

This will enable two different event listener types for listening to Hibernate events:

Global Event Handler

To use a global event handler, you must set a path to the global event handler using the eventHandler setting:

this.ormSettings = {
    eventHandling: true,
    eventHandler : "path/to/global/EventHandler.bx"
};

The EventHandler.bx must then contain function definitions matching the ORM events you wish to listen for.

Currently, the available event names are:

  • onFlush

  • preLoad

  • postLoad

  • preInsert

  • postInsert

  • preUpdate

  • postUpdate

  • preDelete

  • onDelete

  • postDelete

  • onEvict

  • onClear

  • onDirtyCheck

  • onAutoFlush

Here's an example of an EventHandler configured for all events:

class {

	public class function init(){
		return this;
	}

	function onFlush( entity ) {
		// Do something upon function call
	}

	function preLoad( entity ){
		// Do something upon function call
	}
	function postLoad( entity ){
		// Do something upon function call
	}

	function preInsert( entity ){
		// Do something upon function call
	}
	function postInsert( entity ){
		// Do something upon function call
	}

	function preUpdate( entity, Struct oldData  ){
		// Do something upon function call
	}
	function postUpdate( entity ){
		// Do something upon function call
	}

	function preDelete( entity ){
		// Do something upon function call
	}	
	function onDelete( entity ) {
		// Do something upon function call
	}
	function postDelete( entity ) {
		// Do something upon function call
	}

	function onEvict() {
		// Do something upon function call
	}
	function onClear( entity ) {
		// Do something upon function call
	}
	function onDirtyCheck( entity ) {
		// Do something upon function call
	}
	function onAutoFlush( entity ) {
		// Do something upon function call
	}
}

Entity Event Handler

You can also listen to events on a specific entity at the entity level by adding methods to the entity (class) itself:

class persistent="true"{
	function preInsert( entity ){
		setDateCreated( now() );
	}
	function preUpdate( entity ){
		setDateModified( now() );
	}
}

Note that only events related to a specific entity will fire upon that entity. For example, you cannot listen to onFlush in an entity event handler because a flush is not tied to any one entity.

Here is the full list of event types which can be listened to in entity event listeners:

  • preLoad

  • postLoad

  • preInsert

  • postInsert

  • preUpdate

  • postUpdate

  • preDelete

  • onDelete

  • postDelete

Transactions

Learn transaction management with bx-orm

A transaction is any discrete unit of work used to pool database queries and statements to execute at once. This helps us to prevent a failed update from leaving the database in a broken state.

To denote a transaction, we wrap it in the transaction{} tag:

transaction{
    // queries go here
}

The transaction will automatically commit (persist) at the end of the transaction block.

Transaction Rollback

Transaction Commit

Transaction Savepoint

Savepoints are not currently supported on ORM transactions.

Listen to all events across all entities via the

Listen to specific events on a specific entity via methods

This section is missing documentation - would you care to ?

This section is missing documentation - would you care to ?

Looking for ORM savepoint support? .

global event handler
entity event handler
add it yourself
add it yourself
Contact our Support team to consider sponsoring this feature

Caching

Improve your database performance with secondary caching in Hibernate ORM.

Secondary Cache

A secondary cache provider is a class which manages a level of caching that is secondary to Hibernate's main caching context - the Hibernate session. A secondary cache enables longer-running cache contexts, more fine-grained control over cache busting, and other performance-related benefits.

The only setting necessary to enable secondary caching is the secondaryCacheEnabled setting:

this.ormSettings = {
    secondaryCacheEnabled : true
};

To configure the caching, specify the path to an XML cache configuration file in cacheConfig:

this.ormSettings = {
    secondaryCacheEnabled: true,
    cacheConfig          : "./config/ehcache.xml"
};

This ehcache.xml cache configuration then should look something like this:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true" name="default">
    <diskStore path="java.io.tmpdir"/>
        <defaultCache
            maxElementsInMemory="10000" eternal="false"
            timeToIdleSeconds="120" timeToLiveSeconds="120"
            maxElementsOnDisk="10000000" diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
            <persistence strategy="localTempSwap"/>
        </defaultCache>
        <cache
            name="Autos"
            maxElementsInMemory="20"
            overflowToDisk="false"
            eternal="true">
        </cache>
</ehcache>

Configure Each Entity Cache

Notice how our ehcache.xml defines a default cache configuration?

<defaultCache
    maxElementsInMemory="10000" eternal="false"
    timeToIdleSeconds="120" timeToLiveSeconds="120"
    maxElementsOnDisk="10000000" diskExpiryThreadIntervalSeconds="120"
    memoryStoreEvictionPolicy="LRU">
    <persistence strategy="localTempSwap"/>
</defaultCache>

We highly recommend adding a cache configuration for each cacheable entity. This will help you optimize caching, and will silence error logs like the below:

WARN: HHH90001006: Missing cache[default-update-timestamps-region] was created on-the-fly. The created cache will use a provider-specific default configuration: make sure you defined one. You can disable this warning by setting 'hibernate.cache.ehcache.missing_cache_strategy' to 'create'

Here's a quick example. Say we have an Autos.bx persistent class with caching enabled:

class persistent="true" cacheUse="true"{
    // persistent properties...
}

For this entity, we'll want to create a <cache></cache> entry with a name attribute that matches the entity name OR our cacheName class annotation:

<cache
    name="Autos"
    maxElementsInMemory="20"
    overflowToDisk="false"
    eternal="true">
</cache>

Alternate Cache Providers Are Unsupported

While there is a cacheProvider setting, only EHCache (currently) is supported as a secondary cache provider.

this.ormSettings = {
    secondaryCacheEnabled : true,
    // NOT SUPPORTED!
    cacheProvider : "ConcurrentHashMap"
};

Thus, any usage of cacheProvider other than "ehcache" will be ignored.

Harvesting in Spanish - Evangelism With A Heart
www.harvesting.org
Logo
https://github.com/ortus-docs/bxorm