Active Record Pattern
Concepts
- Background
- What is an ORM?
- Data Mapper Pattern
- Adapter Pattern
- Active Record Pattern
- Identity Map
Active Record Pattern
The Active Record Pattern accomplishes similar goals as the Data Mapper Pattern, but with a slightly different implementation. While the Data Mapper Pattern calls for one Mapper
instance per database view/table/collection, the Active Record Pattern wraps each database view/table/collection into a class, with instances of that class corresponding to individual "smart" records in each view/table/collection. These smart records are capable of saving and destroying themselves. JSData's default approach is a combination of the Data Mapper Pattern and the Active Record Pattern.
Tip
While
Mapper
instances can work with POJOs, by default records will be wrapped in theRecord
class, turning them into "smart" records.
Here's are some quick examples to illustrate:
// or import {DataStore} from 'js-data'
import {Container} from 'js-data'
import adapter from './adapter.js'
// or const store = new DataStore()
const store = new Container()
store.registerAdapter('myadapter', adapter, { default: true })
// Mapper instance (Data Mapper Pattern)
store.defineMapper('post')
// Create and save a new post record using the Data Mapper Pattern
store.create('post', {
title: 'Conceptual Overview of JSData'
}).then((post) => {
console.log(post.id) // 1234
// Create and save a new post record using the Active Record Pattern
const post = store.createRecord('post', {
title: 'Components of JSData'
})
return post.save()
}).then((post) => {
console.log(post.id) // 1235
})
// or import {DataStore} from 'js-data'
import {Container} from 'js-data'
import adapter from './adapter.js'
// or const store = new DataStore()
const store = new Container()
store.registerAdapter('myadapter', adapter, { default: true })
// Mapper instance (Data Mapper Pattern)
store.defineMapper('post')
// Update a post record using the Data Mapper Pattern
store.update('post', 1234, {
status: 'published'
}).then((post) => {
console.log(post.id) // 1234
console.log(post.status) // "published"
console.log(post.published_at) // undefined
// Update a post record using the Active Record Pattern
post.published_at = new Date()
return post.save()
}).then((post) => {
console.log(post.id) // 1234
console.log(post.status) // "published"
console.log(post.published_at) // "2016-04-18T15:20:53.949Z"
})
// or import {DataStore} from 'js-data'
import {Container} from 'js-data'
import adapter from './adapter.js'
// or const store = new DataStore()
const store = new Container()
store.registerAdapter('myadapter', adapter, { default: true })
// Mapper instance (Data Mapper Pattern)
store.defineMapper('post')
// Destroy post record using the Data Mapper Pattern
store.destroy('post', 1234).then(() => {
// Destroy a post record using the Active Record Pattern
const post = store.createRecord('post', {
id: 3554
})
// post with id 3554 is destroyed from the database
return post.destroy()
})
Some folks like the convenience of smart records, because as they pass record instances around in their application they can easily create, update, and delete records without turning to a Mapper instance.
One tradeoff to "smart" records is that the extra behavior provided by the class interface takes up property names that you might otherwise use as your column names.
Updated over 7 years ago