DevLearningTools

MODULE 10 · LESSON 03

Object-Relational Mapping (ORM)

Working with database rows as CFC objects instead of raw SQL — enabling ORM, defining a persistent entity, and the core entityNew/entitySave/entityLoad functions.

New lessons are added one at a time as the course gets built out — a graded quiz for each lesson is still on the way.

Every database lesson so far has meant writing SQL directly — a cfquery with a SELECT or an UPDATE statement, spelled out by hand. ORM (Object-Relational Mapping) is a different approach entirely: a row in a database table becomes a CFC object, its columns become properties, and reading or saving that row means calling functions on the object instead of writing SQL at all. ColdFusion's ORM is powered by Hibernate, a well-established Java ORM library, running underneath the CFML layer.

Learning Objectives

After completing this lesson, you'll be able to:

  • Enable ORM for an application in Application.cfc.
  • Define a persistent CFC (an entity) that maps to a database table.
  • Create, load, and save an entity using entityNew, entityLoad, and entitySave.

Enabling ORM in Application.cfc

Tag Syntax
<cfset this.name = "ArtGalleryApp">
<cfset this.ormenabled = "true">
<cfset this.datasource = "cfartgallery">
NOTE

These three settings are the minimum ORM needs: a name for the application, ormenabled turned on, and a datasource for ORM to actually connect to — the same datasource concept covered in the earlier lesson.

Defining a Persistent Entity

A persistent CFC is a regular component with persistent="true" set, plus a cfproperty tag for each column it maps to.

Tag Syntax — Artist.cfc
<cfcomponent persistent="true">
    <cfproperty name="id" column="ARTISTID" generator="increment">
    <cfproperty name="firstName" column="FIRSTNAME">
    <cfproperty name="lastName" column="LASTNAME">
    <cfproperty name="email" column="EMAIL">
</cfcomponent>
NOTE

generator="increment" on the id property means the database auto-generates that primary key value — the same idea as an auto-increment column in plain SQL. If a property's column attribute is left out entirely, the property name itself is used as the column name.

Creating and Saving an Entity

Tag Syntax
<cfset artist = EntityNew("Artist")>
<cfset artist.setFirstName("Marcia")>
<cfset artist.setLastName("Em")>
<cfset EntitySave(artist)>
NOTE

setFirstName() and setLastName() aren't written anywhere in Artist.cfc — ORM generates a getter and setter for every property automatically, the same implicit-accessor behavior covered in the Properties lesson.

Loading an Entity

Tag Syntax
<!--- every row --->
<cfset allArtists = EntityLoad("Artist")>

<!--- by primary key --->
<cfset oneArtist = EntityLoad("Artist", 100, true)>

<!--- filtered --->
<cfset caArtists = EntityLoad("Artist", {state="CA"})>
NOTE

The third argument on the by-primary-key call (true) tells entityLoad to return a single object directly instead of an array containing one object — easy to forget, and a common source of a beginner's first ORM-related error.

Updating and Deleting

Tag Syntax — update
<cfset artist = EntityLoad("Artist", 1, true)>
<cfset artist.setFirstName("Garcia")>
<cfset EntitySave(artist)>
Tag Syntax — delete
<cfset artist = EntityLoad("Artist", 5, true)>
<cfset EntityDelete(artist)>
NOTE

There's no separate "update" function — entitySave() handles both creating a brand-new row and updating an existing one, depending on whether the entity it's given already has a saved primary key.

Why Changes Don't Always Appear Instantly: ormFlush()

ORM doesn't necessarily hit the database the moment entitySave() is called — changes can sit in the current ORM session and get written together, typically at the end of the request. ormFlush() forces every pending change to be written immediately.

CFScript
ormFlush();
NOTE

This matters most right before code that needs to read back data it just wrote through a separate mechanism (a plain cfquery, for instance) in the same request — without a flush, that read might not see the ORM change yet.

Common Beginner Mistakes

Forgetting the third argument on a by-primary-key entityLoad call

entityLoad("Artist", 100) returns an array containing one entity. entityLoad("Artist", 100, true) returns that one entity directly — leaving out true is a frequent source of confusing "array has no such method" errors.

Writing a get/set method that ORM already generates automatically

Every cfproperty on a persistent CFC gets an implicit getter and setter for free — writing your own with the same name just overrides ORM's generated one for no benefit, unless it's genuinely doing something custom.

Expecting entitySave() to always insert a new row

It inserts only when the entity doesn't already have a saved primary key — otherwise it updates the existing row. The same function handles both cases.

Best Practices

  • Keep persistent CFCs focused on data and mapping — business logic tends to belong in a separate service layer that uses the entity, not inside the entity itself.
  • Call ormFlush() when a request genuinely needs a pending ORM change visible to something else immediately, not as a routine habit after every save.
  • Reach for ORM when working with objects and relationships is the more natural fit; plain cfquery is still simpler for a quick report or a one-off complex join.

Interview Questions

What is ORM, in one sentence?

A way of working with database rows as CFC objects — reading and saving data through function calls on an entity, instead of writing SQL directly.

What three settings does Application.cfc need at minimum to enable ORM?

this.name, this.ormenabled set to true, and this.datasource.

What does persistent="true" do on a cfcomponent?

Marks the CFC as an entity that ORM manages — its cfproperty tags map to database columns, and it can be created, loaded, saved, and deleted through ORM's entity functions.

What's the difference between entityLoad("Artist", 100) and entityLoad("Artist", 100, true)?

The first returns an array containing the matching entity. The third argument, true, tells entityLoad to return that single entity directly instead of wrapping it in an array.

Summary

In this lesson, you enabled ORM in Application.cfc, defined a persistent entity with cfproperty mappings, and created, loaded, updated, and deleted rows through entityNew, entityLoad, and entitySave/entityDelete instead of writing SQL directly.

What's Next?

The next lesson covers CRUD Operations — building a complete Create, Read, Update, and Delete flow as real pages. It's shown there with plain queryExecute, but the same page structure works just as well with the entity functions from this lesson instead.