BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE

ortussolutions 100 views 34 slides Apr 24, 2024
Slide 1
Slide 1 of 75
Slide 1
1
Slide 2
2
Slide 3
3
Slide 4
4
Slide 5
5
Slide 6
6
Slide 7
7
Slide 8
8
Slide 9
9
Slide 10
10
Slide 11
11
Slide 12
12
Slide 13
13
Slide 14
14
Slide 15
15
Slide 16
16
Slide 17
17
Slide 18
18
Slide 19
19
Slide 20
20
Slide 21
21
Slide 22
22
Slide 23
23
Slide 24
24
Slide 25
25
Slide 26
26
Slide 27
27
Slide 28
28
Slide 29
29
Slide 30
30
Slide 31
31
Slide 32
32
Slide 33
33
Slide 34
34
Slide 35
35
Slide 36
36
Slide 37
37
Slide 38
38
Slide 39
39
Slide 40
40
Slide 41
41
Slide 42
42
Slide 43
43
Slide 44
44
Slide 45
45
Slide 46
46
Slide 47
47
Slide 48
48
Slide 49
49
Slide 50
50
Slide 51
51
Slide 52
52
Slide 53
53
Slide 54
54
Slide 55
55
Slide 56
56
Slide 57
57
Slide 58
58
Slide 59
59
Slide 60
60
Slide 61
61
Slide 62
62
Slide 63
63
Slide 64
64
Slide 65
65
Slide 66
66
Slide 67
67
Slide 68
68
Slide 69
69
Slide 70
70
Slide 71
71
Slide 72
72
Slide 73
73
Slide 74
74
Slide 75
75

About This Presentation

Feeling lost in the trenches of complex SQL queries and manual database interaction? Join us for a beginner-friendly mission to conquer your data with ColdFusion ORM powered by Hibernate! Whether you're a fresh recruit in the coding field or a seasoned veteran navigating legacy ColdFusion applic...


Slide Content

By Luis Majano
ORM
Battlefield

@lmajano
@ortussolutions
•Salvadorean Born!
•Imported to the USA
•On-loan to Spain!
•Computer Engineering
•CEO of Ortus Solutions
MAJANO
LUIS

Discount Code:CFSUMMIT_ITB

https://github.com/coldbox-samples/Pink-Unicorns-Do-Exist
Examples

➡How to use the ColdFusion ORM
➡When to use the ColdFusion ORM
➡Tips & Trips to master Hibernate ORM
➡Pitfalls to avoid
➡Architectural overviews of ORM
➡Extend ORM
Agenda

➡Object Relational Mapper
➡Maps:
-Objects to tables
-Properties to columns
-Relationships to foreign keys and tables
➡An easier way to persist data vs. boring CRUD SQL
➡Focus on objects instead of data
➡ColdFusion ORM (Abstraction to Hibernate/JPA)
➡Almost Everything in Hibernate works in CF
ORM
What is
?

➡Write less boilerplate boring SQL
➡Increase in productivity
➡Rich Object Models
➡Increased Flexibility
➡Database vendor abstraction
➡OO instead of query-based
➡but…..
BENEFITS

Is it a Silver Bullet ?
➡Just another tool
➡Times you need the power of the database: reports, legacy, sp, etc.
➡Mix and Match
➡There is a learning curve, but it is worth the investment
➡What if you wanted an array of structs, list queries, or data arrays?
Use it Wisely!

coldfusionormbook.com
Enhance yourself!
coldbox-orm.ortusbooks.com
orm-extension.ortusbooks.com

Database(s)
ORM
CFML Application
Persisted Entities
CFML Engine
Config Mappings
ORM+
Architecture Qb/CF
SQL

➡Enabled + Configured via Application.cfc
➡this.ormEnabled = true;
➡this.datasource = “MyDatasource”;
➡this.ormSettings = {}
➡https://cfdocs.org/ormsettings
ORM
Activating

ORM
Settings
BAD
DEFAULTS

BAD
DEFAULTS
Control Data Flushing + Transaction Borders:

ormsettings.flushAtRequestEnd = false
ormsettings.autoManageSession = false
Control Database Dialects (If Possible)
ormsettings.dialect = “MySQLwithInnoDB”

BAD
DEFAULTS
Control Entity Discovery or pay the price!

ormSettings.cfclocation = [ “/models”, “/ext/entities” ]
Great for debugging, NOT for production!
ormSettings.logSql = false

Need
HELP
Need even more debugging?
- Build out the Hibernate MXML
- Show syntax exceptions

ormSettings.saveMapping = true
ormSettings.skipCFCWithError = false

DataBoss - github.com/coldbox-modules/databoss
$> install databoss ORM
Entities &
Metadata
Dynamic
Administrator
Inspect, Analyze, Scaffold
Need
HELP

this.ormSettings = {
// Restrict Entity Locations
cfclocation = [ "/models" ],
// Chose the DB Dialect
dialect = "MySQLwithInnoDB",
// Don’t inspect the database
dbcreate = "none",
// Active caching if needed
secondarycacheenabled = false,
cacheProvider = "ehCache",
// Logging only in development
logSQL = env == “dev” ? false : false,
// Session Management: NEVER TRUE
flushAtRequestEnd = false,
autoManageSession = false,
// Event Handling: Yes Please!
eventHandling = true,
eventHandler = "cborm.models.EventHandler",
// Turn on/off skipping of exceptions on syntax: Maybe!
skipCFCWithError = false
};
ORM
Settings
Better

Logging is your best friend, 4EVER!

1. Application.cfc
2. ExtendedLog4j Logging
this.ormSettings = {
// Logging
logSQL = true,
};
WEB-INF/cfusion/lib/log4j.properties
LOGGING

###--------------- Hibernate Log Settings ------
### Set Hibernate log
log4j.logger.org.hibernate=INFO, HIBERNATECONSOLE
### log just the SQL
log4j.logger.org.hibernate.SQL=DEBUG, HIBERNATECONSOLE
log4j.additivity.org.hibernate.SQL=true
### Also log the parameter binding to the prepared statements.
log4j.logger.org.hibernate.type=DEBUG
### log schema export/update ###
log4j.logger.org.hibernate.tool.hbm2ddl=DEBUG, HIBERNATECONSOLE
### log cache activity ###
log4j.logger.org.hibernate.cache=DEBUG, HIBERNATECONSOLE
#---------------------------------------------
WEB-INF/cfusion/lib/log4j.properties
Log4J
Logging

No Object Modeling
#1 Failure

➡ORM relationship modeling is key
➡OO is required
➡UML is your best friend
➡STOP THINKING ABOUT DATA
➡YOU ARE NOT MODELING A DATABASE
OO Modeling is Key

OO Modeling is Key

Query Object
Data Data + Behavior
OO Modeling is Key

#2 RELATIONSHIPS

one-to-one
Student Metadata
one-to-many
Student Address
many-to-one
User Role
many-to-many
User Permissions
fieldtype=“”
RELATIONSHIPS

➡Unidirectional or Bidirectional
➡Collections can be as arrays or structs
➡Filtered Collections (Missed by devs)
➡Performance Failures
➡Control when they are loaded (lazyness)
➡Control how many related entities are loaded
➡Executing code on loading
➡The hardest part of ORM
RELATIONSHIPS

➡one-to-many, many-to-many
➡add<relationship_property_name>(<associated_object>)
➡boolean remove<relationship_property_name>(<associated_object>)
➡boolean has<relationship_property_name>(<associated_object>)
➡many-to-one, one-to-one
➡boolean has<relationship_property_name>()
•addArts( Art art )
•removeArts( Art art )
•hasArts()
•hasArts( Art art )
property name=“arts"
fieldtype="one-to-many"
cfc="Art"
fkcolumn=“ArtistID";
GENERATED
METHODS

YOU HAVE TO BE
LAZY

➡Immediate Fetching (Default)
➡select with left outer join
poor, poor, poor, poor performance
➡Use lazy For ALL Relationships or pay the price YOU HAVE TO BE
LAZY

➡Three types of laziness values:
lazy=“true”
all relationships
Loads the relationship data when the getter is called (Batches, if used)
lazy=“extra”
one-to-many, many-to-many
Loads proxy light objects with primary keys
(Event better - Batches, if used)
lazy=“proxy”
one-to-one, many-to-one
Loads proxy with primary key (Same as above) YOU HAVE TO BE
LAZY

➡Eager Fetching
➡Mostly used in one-to-one and many-to-one, but applies to all
➡Default uses 2 SQL queries, reduce to 1 Query
property name=“role” fieldtype=“many-to-one” fetch=“join”;
➡Batch Fetching
➡Limits the way relationships are loaded, else Hibernate tries to load all records
➡Used on many-to-many and one-to-many collection properties:
property name=“comments” fieldtype=“one-to-many” batchsize=“10” lazy=“extra”;
➡Used at entity level as well:
component name=“Comment” batchsize=10{} YOU HAVE TO BE
LAZY

Oracle Tip
➡JDBC Fetch Sizes are defaulted to 10
➡Slow for many records or batch operations
➡Increase the JDBC Fetch size
➡Custom Hibernate setting
hibernate.jdbc.fetch_size=100 YOU HAVE TO BE
LAZY

➡They can be more of a headache
➡Cascading Deletes are painful
➡Choose the controlling relationship
➡inverse=true
➡Else double queries, inefficient queries
➡Does it make sense?
➡Supporting methods for bi-directional linkage
➡Supporting methods for un-linkages
AVOID BI-DIRECTIONAL,
IF POSSIBLE!

BETTER Relationships

➡Not the same as session scope
➡A transitionary space + Caching Layer
➡entityLoad()
➡entityNew() ?
➡You need to control when to send to DB
➡transaction{}, ormflush()
➡You can remove entities from it and clear it
➡ORMClearSession()
➡ORMEvictEntity(), ORMEvictCollection()
➡ORMCloseSession()
UNDERSTAND THE HIBERNATE SESSION

Hibernate Session
(Conversation - Request)
DB
Eu
Ex EzEy
Cache
ehCache/
Couchbase
Batched SQL
EntityNew()
EntityLoad()
Data (!CFCs)
Hibernate Session
Factory (application)
CRUD
When?
ORMClearSession()
UNDERSTAND THE HIBERNATE SESSION

DB Sync
Insertions in order
updates
Collection deletions
collection deletion, updates, inserts
collection insertions
deletions in order
UNDERSTAND THE HIBERNATE SESSION

➡Transactions demarcate SQL boundaries
➡Important Imperative for ORM + SQL
➡No communication to DB should occur without one
➡Reactive programming, expect the worst
➡cftransaction or Hibernate raw transactions
TRANSACTION DEMARCATION

➡Transaction Theory:
➡Any existing ORM session is flushed and reused
➡Data can be committed or rollback
➡ORMFlush() is ignored in transactions
➡If commit, then flushed to database
➡If rollback, session is cleared
TRANSACTION DEMARCATION

TRANSACTION DEMARCATION

TRANSACTION DEMARCATION

➡Don’t do it!
➡Breaks the link to the Hibernate Session
➡Relationships will fail if not lazy loaded
➡entityMerge()
➡Store ID’s or data instead, then inflate the entities
AVOID SCOPING ENTITIES

➡#1 Performance Problem
➡Identify relationships
➡Identify HQL, SQL
➡Create indexes!
DATABASE
INDEXES

➡Don’t go cache crazy, develop a strategy
➡Misconception: Does not store CFC
➡Stores individual property values
➡Use distributed caches: ehcache, couchbase, redis
➡You can cache:
➡Entity property data : Only caches properties data values
➡Entity association data : Only caches primary keys
➡Query data : HQL, ORMExecuteQuery()
➡Evictions:
➡ORMEvictEntity(), ORMEvictCollection()
CACHE
BOOSTING

CACHE
BOOSTING

CACHE
BOOSTING

➡The fastest gun in the galaxy!
➡Return array of structs
➡Why a full ORM Object graph?
➡Boost your APIs, stop converting queries/
array of objects to JSON HQL
MAPS

HQL
MAPS

When is HappyBox?
ORM was fast
Extensible way to finish
the remaining 20%
CF ORM was easier to use?
80% of API Querying
OO way to query
Auto build relationships
ORM
THOUGHTS?

Base ORM Service
Virtual ORM Service
Active Entity
Entity Populators
Validation
Event Handlers
DI/AOP
OVERVIEW

➡Service layer for any entity
➡OO Querying, caching, transactions
➡Dynamic finders, getters, counters
➡Object metadata & session management
➡Exposes more features from Hibernate
➡90% Foundation
BASE ORM
SERVICE

➡Extends Base ORM Services
➡Roots itself to a single entity = Less Typing
➡You can build the 10%
VIRTUAL
SERVICES

➡Active Record Pattern
➡Sweet validation integration
➡DI/AOP Available
ACTIVE
ENTITY

➡Populate Entities: xml, json, queries, structs
➡Compose relationships from simple values
➡Null support
➡Exclude/include fields
➡Server-side validation
➡Dependency Injection Listeners
➡Custom Event-Driven Programming
Entity Populators
Validation
Event Handlers
ORM
UTILITIES

box install cartracker-demo.
ORM
SERVICES
IN ACTION

➡count(), countWhere()
➡delete(), deleteAll(), deleteByID(), deleteByQuery(), delete Where()
➡evict(), evictEntity(), evictQueries()
➡executeQuery(), list()
➡exists()
➡findAll(), findAllWhere(), findByExample(), findIt(), findWhere()
➡get(), getAll(),
➡getKey(), getPropertyNames(), getSessionStatistics(), getTableName()
➡clear(), merge(), new(), refresh()
➡populate(), populateFromJSON(), populateFromXML(), populateFromQuery()
➡save(), saveAll()
BASE ORM
SERVICE

BASE ORM
SERVICE
Dynamic Finders/Counters
➡Expressive Programming
➡Three types of dynamic Finders/Counters
➡findBy : find ONE entity
➡findAllBy : find ALL entities
➡countBy: Give you a count

BASE ORM
SERVICE
Dynamic Finders/Counters
➡Conditionals
➡LessThanEquals, LessThan
➡GreaterThanEquals, GreaterThan
➡Like
➡Equal, NotEqual
➡isNull, isNotNull
➡Between, NotBetween
➡inList, notInList
➡Operators
➡And
➡Or
➡Query Options
➡ignoreCase, timeout, max, offset
➡cacheable, cachename

AWESOME OO QUERIES
CRITERIA
BUILDER

CRITERIA
BUILDER
➡Limitations of CF ORM:

entityLoad() has limited features
➡Some operations we always need an entity =
slow
➡What if I want arrays, or arrays of structs
➡Complex relationships are hard to query
➡SQL/HQL string build is so 90’s == NOT FUN!

CRITERIA
BUILDER
➡Programmatic DSL Builder
➡Rich set of criterias
➡Projections and Result transformations
➡Subqueries
➡Caching
➡SQL Inspections & Debugging
➡Array of structures is twice as fast as
queries

CRITERIA
BUILDER

CRITERIA
BUILDER
➡Request new criteria
➡newCriteria()
➡Add simple restriction(s)
➡Find all cars sold between April and July
➡Use between()
➡Get results
➡Use list( max, offset, timeout, sortOrder, ignoreCase, asQuery )
➡Get counts
➡Use count()

CRITERIA
BUILDER
➡between()
➡eq()
➡gt()
➡ge()
➡gtProperty()
➡isEmpty()
➡isNull()
➡ne()
➡ilike()
➡and()
➡or()
➡not()
➡conjunction()
➡disjunction()
➡isTrue()
➡isFalse()
➡sqlRestriction()
➡...much more!
RESTRICTIONS

CRITERIA
BUILDER
RETRIEVALS
➡Retrieval
➡firstResult()
➡get()
➡list()
➡count()
➡Options
➡fetchSize()
➡readOnly()
➡maxResults()
➡cache(), cacheRegion()
➡timeout()
➡order()

CRITERIA
BUILDER
ALIASES-> JOINS
➡Allows you to do queries within relationships
➡Creates SQL Joins
➡Aliases can be nested, so if your entity knows
about it, you can query it!

CRITERIA
BUILDER
PROJECTIONS
➡Projects change nature of results
➡Arrays of data, or arrays of structs (Mighty Fast)
➡Once its added its there forever
➡avg
➡count
➡countDistinct
➡distinct
➡groupProperty
➡max
➡min
➡property
➡sum
➡rowCount
➡id
➡sqlProjection
➡sqlGroupProjection
➡detachedSQLProjection

CRITERIA
BUILDER
DEBUGGING + LOGGING
➡Criteria Builder SQL Inspector
➡startSQLLog( returnExecutableSQL, formatSQL )
➡stopSQLLog()
➡getSQLLog()
➡getSQL( returnExecutableSQL, formatSQL )

Thank You
By Luis Majano