The ORM support in BreezeDb allows you to seamlessly map each database table to an ActionScript class (model). Models give you the ability to query for data in your tables, as well as insert new records into the table using strongly typed objects.
You can define model for all or only some of your tables as you see fit. In any case, a model must subclass the base BreezeModel
class:
public class Photo extends BreezeModel
{
public var id:int;
public var title:String;
public var views:int;
public var downloads:int;
public var creation_date:Date;
}
All public variables represent the respective columns in the table.
Although you may specify default values in the database schema, the default values that you provide in the model class will override any in the schema:
public class Photo extends BreezeModel
{
public var id:int;
public var title:String = "Default Title";
...
}
It is also possible to initialize the model by passing in a key-value Object
to the super()
call:
public class Photo extends BreezeModel
{
public var id:int;
public var title:String;
...
public function Photo()
{
super({ title: "Default Title" });
}
}
The name of the table corresponding to the model is automatically derived from the model's class name using "snake case" and plural form.
Class name | Table name |
---|---|
Photo |
photos |
PhotoAlbum |
photo_albums |
You can also explicitly specify the table name if you wish by setting the protected _tableName
variable in the model's constructor:
public class Photo extends BreezeModel
{
...
public function Photo()
{
super();
_tableName = "my_photos";
}
}
If not explicitly set, each model uses the default BreezeDb database. If you are using a custom database, you need to manually set the _databaseName
variable in the model's constructor:
BreezeDb.getDb("my_database").setup(...);
...
public class Photo extends BreezeModel
{
...
public function Photo()
{
super();
_databaseName = "my_database";
}
}
By default each table is assumed to have a primary key column named id
. You can change the primary key name using the _primaryKey
variable. You can also pass a value of null
if there is no primary key in the table:
public class Photo extends BreezeModel
{
public var title:String;
...
public function Photo()
{
super();
// 'title' is now the primary key
_primaryKey = "title";
}
}
By default the primary key is considered to be auto-incrementing. You can change this by setting the _autoIncrementId
variable to false
:
public class Photo extends BreezeModel
{
...
public function Photo()
{
super();
_autoIncrementId = false;
}
}
Models can be queried using the BreezeModelQueryBuilder
class. It is a subclass of BreezeQueryBuilder
which means you get access to all the existing query methods plus some more. Additionally, the model builder automatically casts the results to your custom model's class so you get to work with strongly typed objects.
To start querying your custom model, you need to obtain a reference to an instance of BreezeModelQueryBuilder
that is associated with your model's class. You can either create the instance manually by passing your model's class to the constructor of the model builder, or use the static query
method provided by BreezeModel
:
// 'Photo' is the class of our custom model
var builder:BreezeModelQueryBuilder = new BreezeModelQueryBuilder(Photo);
var builder:BreezeModelQueryBuilder = BreezeModel.query(Photo);
To further increase the readability of your code, you could create a static query
method directly on your model's class:
public class Photo extends BreezeModel
{
...
public static function query():BreezeModelQueryBuilder
{
return new BreezeModelQueryBuilder(Photo);
}
}
...
var builder:BreezeModelQueryBuilder = Photo.query;
After you have a BreezeModelQueryBuilder
reference you can query it just like you would with the BreezeQueryBuilder
:
Photo.query.first(function(error:Error, first:Photo):void
{
if(first != null)
{
trace(first.title);
}
});
As you can see, using the model builder gives you the ability to type the callback parameters to your model's class and not a generic Object
.
This also applies to queries where a Collection
is returned. Each object within the collection is an instance of your model:
Photo.query
.select("id", "title")
.where("id", "<", 10)
.fetch(function(error:Error, photos:Collection):void
{
if(error == null)
{
for each(var photo:Photo in photos)
{
trace(photo.id, photo.title);
}
}
})
The model builder has an additional method that allows you to retrieve models by primary key. This functionality is provided by the find
method:
// Find photo with id of 2
Photo.query.find(2, function(error:Error, photo:Photo):void
{
if(photo != null)
{
trace(photo.id); // 2
}
});
You may also pass in an Array
of primary keys to retrieve multiple models:
// Find photos with id of 1, 2 and 3
Photo.query.find([1, 2, 3], function(error:Error, photos:Collection):void
{
if(error == null)
{
for each(var photo:Photo in photos)
{
trace(photo.id);
}
}
});
All aggregate functions provided by query builder are also available to use with your models:
// Return number of photos that have more than 100 views
Photo.query.where("views", ">", 100).count(function(error:Error, count:int):void
{
trace(count);
});
To insert new records into your model's table, simply create an instance of the model, set its properties and call the save
method. The callback method gives you access to the model that has just been saved:
var photo:Photo = new Photo();
photo.title = "Sunset";
photo.views = 10;
photo.downloads = 3;
photo.save(function(error:Error, savedPhoto:Photo):void
{
});
After an insert has been completed, the primary key (if applicable) will be set and the exists
property will be true
:
var photo:Photo = new Photo();
trace(photo.exists); // false
photo.save(function(error:Error, savedPhoto:Photo):void
{
// savedPhoto.id is now set
trace(savedPhoto.exists); // true
});
The save
method can also be used to update an existing model. For example, you could use the find
method to retrieve a specific model, update its properties and save it back to the database:
// Find photo with id of 1 and update its title
Photo.query.find(1, function(error:Error, photo:Photo):void
{
// Model not found
if(photo == null)
{
return;
}
photo.name = "Sunrise";
photo.save(function(error:Error, savedPhoto:Photo):void
{
if(error == null)
{
// Photo has been updated
}
});
});
To update several models at once, use the update
method, preferably with the where
method:
// Reset downloads for photos with 100 or more views
Photo.query.where("views", ">", 100).update({ downloads: 0 }, function(error:Error, rowsAffected:int):void
{
trace("Updated", rowsAffected, "photo(s)");
});
The firstOrNew
method gives you the ability to search the database for a model with given values, and if one is not found, retrieve a new instance with the values already set on the model. Note that if the model is not found then the returned instance has not been persisted to the database yet and you will need to call the save
method manually to do that:
Photo.query.firstOrNew({ title: "Sunset" }, function(error:Error, photo:Photo):void
{
if(error == null)
{
trace(photo.title); // Sunset
}
});
The firstOrCreate
method is very similar, except that the model is automatically saved into the database if it is not found during the lookup:
Photo.query.firstOrNew({ title: "Sunset" }, function(error:Error, photo:Photo):void
{
if(error == null)
{
trace(photo.title); // Sunset
trace(photo.exists); // true
}
});
To delete a specific model, call the remove
method on the model's instance:
Photo.query.find(1, function(error:Error, photo:Photo):void
{
photo.remove(function(deleteError:Error):void
{
if(deleteError == null)
{
// Photo has been deleted
}
});
});
The removeByKey
methods is a shortcut to the approach above. If you know the model's primary key, you can delete it directly without retrieving it first:
// Delete photo with id of 1
Photo.query.removeByKey(1, function(error:Error):void
{
});
You can also delete multiple models by providing an Array
of primary keys:
// Delete photos with id of 1, 2 and 3
Photo.query.removeByKey([1, 2, 3], function(error:Error):void
{
});
You may also use use the remove
method to delete several models at once. Use it together with the where
method to avoid deleting all the records in the table:
// Delete photos with more than 15 views
Photo.query.where("views", ">", 15).remove(function(error:Error):void
{
});