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
<cfset this.name = "ArtGalleryApp"> <cfset this.ormenabled = "true"> <cfset this.datasource = "cfartgallery">
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.
<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>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
<cfset artist = EntityNew("Artist")>
<cfset artist.setFirstName("Marcia")>
<cfset artist.setLastName("Em")>
<cfset EntitySave(artist)>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
<!--- every row --->
<cfset allArtists = EntityLoad("Artist")>
<!--- by primary key --->
<cfset oneArtist = EntityLoad("Artist", 100, true)>
<!--- filtered --->
<cfset caArtists = EntityLoad("Artist", {state="CA"})>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
<cfset artist = EntityLoad("Artist", 1, true)>
<cfset artist.setFirstName("Garcia")>
<cfset EntitySave(artist)><cfset artist = EntityLoad("Artist", 5, true)>
<cfset EntityDelete(artist)>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.
ormFlush();
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.