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 = "Address"
fieldtype = "one-to-one"
class = "Address";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 = "Address"
fieldtype = "one-to-one"
class = "Address"
lazy = "false";This one-to-one relationship can be visualized as follows:

Constrained (constrained)
The constrained attribute is specific to one-to-one relationships. When set to true, it declares that the owning entity's primary key has a foreign-key constraint pointing to the associated entity's primary key — in other words, the associated record must exist:
property name = "userProfile"
fieldtype = "one-to-one"
class = "UserProfile"
constrained = "true";Use constrained=true when the UserProfile table's primary key is also a foreign key back to the User table (a shared-primary-key one-to-one). Without it, Hibernate treats the association as a simple reference with no FK constraint generated in the schema.
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"):
You'll normally want to set lazy="true" to (for example) avoid fetching every Post on a User:

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"):
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 the author/book relationship. Each book can have multiple authors, and each author may write multiple books:
The linktable attribute is required on a many-to-many property to set the location for storing join records. You can further alter the storage location via linkschema and linkcatalog:

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:
Lazy Loading
The lazy attribute controls when Hibernate fetches the related data — immediately when the owning entity is loaded, or deferred until the data is actually accessed. Choosing the right strategy can have a significant impact on performance.
false
all
Related data is fetched immediately in the same SQL query (eager loading).
true
all
Related data is fetched lazily; Hibernate issues a separate SQL query only when the association is first accessed.
proxy
to-one (many-to-one, one-to-one)
Like true, but the related entity is replaced with a lightweight proxy object. The real entity is loaded only when a non-identifier getter is called.
extra
to-many (one-to-many, many-to-many)
Like true, but even more granular — aggregate operations (size(), contains(), etc.) are resolved without loading the full collection.
lazy=false — Eager Loading
Eager loading fetches the association in the same query as the parent entity. This is most useful for to-one relationships where the related data is almost always needed:
Avoid using lazy=false on to-many collections — fetching large collections eagerly can significantly inflate query result sets.
lazy=true — Lazy Loading
Related data is not fetched until you first access it. A separate SQL query is issued at that point:
For to-one relationships, lazy=true behaves identically to lazy=proxy when the application-level proxyLazyLoading setting is enabled (see below).
lazy=proxy — Proxy-Based Lazy Loading
Only valid on to-one relationships (many-to-one, one-to-one). Hibernate returns a proxy object in place of the real entity. The proxy holds the primary key so that identity checks work without hitting the database; the real entity is loaded only when you call a non-identifier getter:
This is the most efficient lazy strategy for to-one associations. When the proxyLazyLoading application setting is true, BoxLang ORM automatically upgrades lazy=true to lazy=proxy for all to-one properties (see below).
lazy=extra — Extra Lazy Collection Loading
A more granular form of lazy loading for to-many collections. Aggregate operations on the collection (checking size(), calling contains(), etc.) are resolved with targeted SQL without loading the full collection into memory:
Use lazy=extra when you frequently need collection metadata (e.g. counts) but rarely iterate over the full set.
proxyLazyLoading Application Setting
The proxyLazyLoading boolean in your Application.bx ORM settings controls whether lazy=true is automatically promoted to lazy=proxy for to-one relationships at mapping time.
proxyLazyLoading = false
lazy=true on a to-one stays as Hibernate lazy=true (standard lazy fetch)
proxyLazyLoading = true
lazy=true on a to-one is rewritten to lazy=proxy (proxy-based lazy fetch)
Note:
proxyLazyLoadingdefaults tofalsein BoxLang ORM to match Adobe ColdFusion and Lucee behaviors. If you are migrating from ACF or Lucee and rely on proxy-based lazy loading, you must explicitly setproxyLazyLoading = true, or installbx-compat-cfmlwhich restores the legacy default.
Cascade
The cascade attribute controls which persistence operations performed on the owning entity are automatically propagated to the associated entity or collection. Without a cascade setting, you must explicitly save, delete, or update each related entity yourself.
none
No operations are cascaded. Each entity must be persisted independently. (Default)
all
All operations below are cascaded.
save-update
EntitySave() on the owner also saves or updates the related entity.
persist
JPA-style alias for save-update.
merge
Merging the owner into the session also merges the related entity.
delete
Deleting the owner also deletes the related entity.
remove
JPA-style alias for delete.
refresh
Refreshing the owner from the database also refreshes the related entity.
evict
Evicting the owner from the session cache also evicts the related entity.
lock
Locking the owner into the session also locks the related entity.
replicate
Replicating the owner also replicates the related entity.
You can combine multiple values as a comma-separated string:
With cascade="save-update,delete", calling EntitySave( user ) will automatically persist any new or modified Post objects in the collection, and calling EntityDelete( user ) will delete all of the user's posts first.
Warning: Use
cascade="all"orcascade="delete"carefully on large collections. Deleting aUserwith thousands of posts will issue a DELETE for each one individually unless you configure bulk operations at the database level.
Fetch Strategy
The fetch attribute controls how Hibernate retrieves the association when it does load — as a SQL JOIN in the same query, or as a separate SELECT:
select
Hibernate issues a separate SELECT query to load the association. (Default)
join
Hibernate uses a SQL JOIN to load the association in the same query as the parent.
fetch=join forces eager loading regardless of the lazy setting and is most useful on to-one associations where the related data is almost always needed. Avoid it on to-many collections, as it can multiply the result-set rows.
Ordering Collections (orderBy)
The orderBy attribute applies a SQL ORDER BY clause whenever Hibernate loads a to-many collection. The value is a raw SQL fragment:
The collection returned from getPosts() will always be sorted by created_at descending. This is applied at the database level, not in memory.
Filtering Collections (where)
The where attribute applies a fixed SQL WHERE condition to a collection, restricting which rows are ever included. The value is a raw SQL fragment (not HQL):
getPosts() will only ever return rows where status = 'published'. This is useful for modelling a filtered view of a collection without a separate entity query.
Inverse and Bidirectional Relationships
When you model a relationship from both sides (e.g. User has posts and Post has author), only one side should "own" the foreign key and be responsible for writing it to the database. The other side is the inverse side and should be marked accordingly to avoid Hibernate attempting to update the join column twice.
Use inverse=true to mark a collection as the non-owning side:
Alternatively, use mappedBy on the collection to name the property on the child entity that owns the join:
Both inverse=true and mappedBy tell Hibernate the same thing: this collection side does not manage the foreign key. For one-to-many / many-to-one pairs, always mark the collection side as inverse (or use mappedBy). For many-to-many, pick one side.
Batch Size (batchsize)
The batchsize attribute overrides the global defaultBatchSize ORM setting for this specific collection, controlling how many collections Hibernate fetches in a single round-trip when multiple parent entities are loaded:
If you load 100 User entities and then access each one's posts, Hibernate will fetch them in batches of 50 rather than issuing 100 individual SELECT queries.
When no per-property batchsize is set, Hibernate falls back to the application-wide defaultBatchSize ORM setting (see Configuration). BoxLang ORM defaults defaultBatchSize to 25, while Adobe ColdFusion and Lucee both historically default to 16. If you are migrating from ACF/Lucee and want matching batch-fetch behavior, set defaultBatchSize=16 in your this.ormSettings, or install bx-compat-cfml which restores the legacy default.
Relationship Methods
When you define a relationship property, a number of methods are automatically generated in each relationship entity instance which allow you to access and manipulate the relationship data.
has<PropertyName>()
Returns true if the relationship contains any items.
All
add<PropertyName>( entity1 )
Add an entity instance to the relationship.
one-to-many, many-to-many
remove<PropertyName>( entity1 )
Removes one or more entities from the relationship.
one-to-many, many-to-many
These method signatures are as follows:
One-To-One Example
The following relationship definition defines a Contact property on a User entity:
Since this is a one-to-one relationship, only the hasContact() method is generated:
hasContact()
Use the property accessor methods getContact() and setContact() to access and modify the relationship.
One-To-Many Example
The following relationship definition defines a posts property on a User entity:
Since this is a one-to-many relationship, the following methods are generated:
hasPosts()addPosts()removePosts()
Singular Name
We can set a singularName attribute to change the addPosts() and removePosts() methods to addPost() and removePost():
This will generate the following methods:
hasPosts()addPost()removePost()
Note that the hasPosts() method remains plural since it checks for the existence of any posts in the relationship.
Last updated
Was this helpful?