Definition
A ColdFusion Persistent Component is a ColdFusion Component (CFC) that is mapped to a database table and managed by ColdFusion ORM (Object-relational mapping). Declaring a component as persistent tells ColdFusion to treat it as a database-backed entity—automatically handling CRUD operations, identity, relationships, and caching through Hibernate. Put simply: a persistent component is an object that ColdFusion knows how to store, retrieve, and relate to other objects without you writing raw SQL for every operation.
How It Works
Under the Hood: ColdFusion ORM and Hibernate
- ColdFusion ORM is a layer on top of Hibernate, a mature Java ORM library.
- When you mark a CFC with
persistent="true", ColdFusion generates an entity mapping from the component and itscfpropertytags/metadata. - ORM handles:
- Identity (primary keys, sequences, generated IDs).
- Relationships (one-to-many, many-to-one, many-to-many).
- Fetching strategies (lazy vs. eager loading).
- Transactions and dirty checking (tracking changes to objects).
- Caching (first-level session cache and optional second-level cache).
Lifecycle in a Request
- Your ColdFusion app starts with ORM enabled in
Application.cfc. - On first ORM access (or after an
ORMReload()), ColdFusion builds mappings. - You create or load entities with functions such as entityNew, entityLoad, entitySave, entityDelete.
- ORM keeps track of Object state in a session. When you save or commit a transaction, Hibernate generates SQL and syncs changes to the database.
Syntax and Basic Example
Application Configuration (Application.cfc)
cfm
component {
this.name = “MyApp”;
this.datasource = “myDSN”;
this.ormEnabled = true;
this.ormSettings = {
dbcreate = “update”, // validate | update | create | dropcreate
cfclocation = [“model”], // folder(s) containing CFCs
logSQL = true
};
}
Defining a Persistent CFC (cfcomponent)
cfm
Using the Entity (cfscript)
cfm
user = entityNew(“User”);
user.setEmail(“alice@example.com”);
user.setPassword(“strongP@ssw0rd”);
entitySave(user); // INSERT
loaded = entityLoad(“User”, {email=”alice@example.com”}, true); // unique result
writeDump(loaded.getId()); // read ID
entityDelete(loaded); // DELETE
Key attributes to notice
persistent="true": marks the CFC as an ORM entity.cfpropertywithfieldtype="id": defines the primary key.ormtypeandcolumn: map CF datatypes to DB columns.- Lifecycle functions like entitySave and entityLoad simplify persistence.
Relationships and Mappings
One-to-Many and Many-to-One Example
Order and OrderItem are classic related entities.
cfm
one-to-manyon Order references many OrderItems.many-to-oneon OrderItem points back to Order viafkcolumn.cascade="all-delete-orphan"ensures item rows are saved/removed with the parent entity.
Real-World Use Case: E‑commerce Order Management
An online store needs to create orders, attach items, and calculate totals. With Persistent components:
- Create an
Orderentity with a generatedorderNumber. - Create several
OrderItementities and associate them with theOrder. - Persist the order in a single unit:
cfm
order = entityNew(“Order”);
order.setOrderNumber(“A100234”);
items = [];
arrayAppend(items, entityNew(“OrderItem”, {sku=”ABC-123″, qty=2, price=19.99}));
arrayAppend(items, entityNew(“OrderItem”, {sku=”XYZ-555″, qty=1, price=249.00}));
order.setItems(items);
transaction {
entitySave(order); // cascades to items
}
The ORM manages inserts, foreign keys, and cascades, removing a lot of boilerplate SQL and helping the team move faster.
Use Cases
- Domain-driven apps where objects map closely to business entities (Users, Orders, Invoices).
- Rapid CRUD development for admin dashboards.
- Apps that benefit from lazy loading, relationship management, and transactional persistence.
- Teams migrating from hand-written SQL to a more declarative data model.
Best practices
Modeling and Mapping
- Prefer explicit
table,column, andormtypedefinitions for clarity. - Always define an ID property with a clear generator (e.g.,
native,identity,uuid). - Name relationships carefully; use
fkcolumnto make DB constraints predictable.
Performance and Fetching
- Default to lazy loading on collections; use
eager="true"only when necessary. - Batch operations within cftransaction/transaction blocks to reduce round-trips.
- Consider enabling second-level cache and query cache for read-heavy entities.
Validation and Security
- Validate input before
entitySave(e.g., email format, length checks). - Store password hashes, not plain text. Keep crypto in component methods to centralize logic.
- Whitelist properties exposed to serialization to avoid leaking sensitive fields.
Operational Tips
- Use
ORMReload()during development to reflect mapping changes; avoid in production. - Control schema generation via
dbcreate(e.g.,validatein production). - Log SQL (
logSQL=true) in dev/test to diagnose N+1 queries or inefficient fetch patterns.
Common pitfalls
- Over-eager loading entire object graphs, causing Performance issues.
- Forgetting to define indexes/constraints in the database, resulting in Slow queries.
- Relying on
dbcreate=createin production, accidentally dropping tables. - Mixing raw SQL and ORM without clear boundaries, leading to stale caches or inconsistent transactions.
- Not handling lazy initialization outside an ORM session (e.g., after the request ends).
Comparison: Persistent Component vs. Regular CFC
-
Persistent CFC:
- Declared with
persistent="true". - Mapped to a database table; managed by ORM/Hibernate.
- Lifecycle and relationships are automatically handled.
- Accessed with helpers like entityLoad, entitySave.
- Declared with
-
Regular CFC:
- Plain object without ORM metadata.
- No automatic persistence; you write queries yourself.
- Full control over SQL but more boilerplate and manual mapping.
Pros and cons
-
Pros:
- Faster development for CRUD and relational data.
- Consistent domain model; less boilerplate SQL.
- Built-in transactions, caching, and lifecycle management.
-
Cons:
- Learning curve around mappings and fetch strategies.
- Performance tuning required for complex graphs.
- Less control over SQL for highly optimized queries.
Key Points
- A ColdFusion persistent component is an ORM-managed entity mapped to a database table.
- Use
persistent="true"andcfpropertymetadata to define identity and fields. - Enable ORM in
Application.cfcwiththis.ormEnabled=true. - Operate via helpers like entityNew, entityLoad, entitySave, and entityDelete.
- Tune performance with lazy loading, transactions, and caching.
Troubleshooting and Debugging
- Turn on
logSQLand review Server logs for generated queries. - Use
ORMReload()after mapping changes during development. - Diagnose N+1 query issues by checking when collections are fetched; adjust
lazy/eagersettings. - Validate that
cfclocationpoints to all entity folders. - Confirm datasource permissions (create/update) match your
dbcreatemode.
Security Considerations
- Secure sensitive fields (e.g.,
passwordHash) and avoid exposing them via APIs. - Use transactions to prevent partial writes that could corrupt state.
- Apply parameterized queries when mixing ORM with raw SQL, and rely on ORM’s parameterization for entity operations.
- Validate and sanitize inputs before saving entities to mitigate injection or logic errors.
FAQ
What is the difference between ColdFusion ORM and Hibernate?
ColdFusion ORM is an abstraction layer built into Adobe ColdFusion and powered by Hibernate under the hood. You configure mappings with CFC metadata instead of writing Hibernate XML or annotations directly, but the persistence engine is Hibernate.
Do I still need SQL if I use Persistent components?
Often less, but not none. ORM covers typical CRUD, relationships, and many queries. For complex reports or highly optimized queries, you may still use raw SQL or HQL, or call stored procedures alongside ORM.
How do I handle Database schema changes with ORM?
Use this.ormSettings.dbcreate:
validatefor production (checks mappings against the schema).updatefor dev/test to apply incremental changes.- Avoid
createordropcreatein production. Use migrations or DBA-managed scripts for safety.
Yes. Use lazy="true" (default) to defer loading until accessed, or eager="true" to fetch immediately. Choose per relationship and tune based on usage to avoid N+1 queries.
What happens if I change an entity and don’t call entitySave?
If the entity is attached to the current ORM session and the request commits a transaction, Hibernate’s dirty checking can flush changes automatically. To be explicit and predictable, call entitySave within a transaction for important changes.
