CSC/ECE 517 Fall 2013/ch1 1w43 av: Difference between revisions
Line 291: | Line 291: | ||
Key Features | ===Key Features=== | ||
*Thread safety, connection pooling | *Thread safety, connection pooling |
Revision as of 00:10, 6 October 2013
Introduction
Object-relational mapping (ORM) provides developers with a set of tools that ease management of the relationships between objects and relational databases, thus allowing applications to be easily extended to add data persistence. For Ruby, several object-relational mapping options are available. This wiki concentrates more on the comparison of ORMs and provides a high level overview of the top Ruby ORMs: ActiveRecord ,Sequel and DataMapper. It also includes a minor discussion on alternative frameworks that can be used either in place of or along with ORMs. These include the persistence framework iBATIS (more specifically the Ruby version RBatis).
Overview
Object-relational Mapping (ORM) frameworks unburden the designer of the complex translation between database and object space.
ORM features constitutes the following:
- It binds an object to its data in the database.
- Class instance variables to database columns
- Class instances to table rows
- It depicts associations, properties and behaviors related to tables and their fields.
- Example, :has_many, :belongs_to associations in ActiveRecord
- Inheritance cases are mapped to tables
- It manages the process of converting data between its database and object forms.
- It performs validation of data before it is persisted to table storage.
- It generates the SQL for a relational database to perform Create Read Update Delete operations in response to the changes made to the data objects within the application.
The diagram below depicts a simple mapping of an object to a database table….
The Need for ORM
A relational database has been the preferred mechanism for storing data requiring large storage space. An RDMBS provides users efficient create, read, update and delete operations. The efficiency of ORM technique of exchanging data between a relational db and an object oriented language surpasses the traditional techniques of data exchange.
The previously popular database products like structured query language had the disadvantage that they can operate over scalar values that have been organized in tabular format. This is where object relational mapping comes in the picture. It converts the object values into values suitable to be stored in the database. ORM helps in mapping between the logical business model and physical storage model . This gives the user the opportunity to model entities based on actual business requirements rather than the structure of the database. Object Relation mapping basically determines how objects and their relationships are persisted in permanent data storage.
A database ORM is an abstraction of a database. Few popular Ruby ORMs include Active Record, Data Mapper and Sequel. By enabling database rows to be used as objects, the program can more easily access and use the information in a way that is internally consistent and easy to understand. The ORM gives the programmer to manipulate data with the programming language, instead of having to manipulate each attribute as its data type as obtained by the database management system.
When applied to Ruby, implementations of ORM often leverage the language’s metaprogramming strengths to create intuitive application-specific methods and otherwise extend classes to support database functionality. With the addition of Rails, the ORM becomes much more important, as it is necessary to have an ORM to connect the models of the MVC (model-view-controller) stack used by Ruby on Rails with the application's database. Since the models are Ruby objects, the ORM allows modifications to the database to be done through changes to these models, independent of the type of database used. Following are some of the popular ORM tools.
Active Record
ActiveRecord is the Object-Relational Mapping system. Ruby on Rails web application framework uses this system.
- It is based on “convention over configuration” in order to provide defaults to meet most developers needs.
- For instance, if you create a table in your database names user and add a Ruby class called User to your Rails application, ActiveRecord can figure out that the two are connected.
- The table can then be used for searching instances and returning specific values.
- It will also auto generate unique ids for each instance and will even generate attributes that will track, for instance, creation of a row and latest update of a row.
Naming Conventions
By default, Active Record uses some naming conventions to find out how the mapping between models and database tables should be created.
Model/class Table/schema User users Userpost user_posts Person people
Creating an ActiveRecord model:
Step 1.Create a subclass of ActiveRecord::Base
class User < ActiveRecord::Base end class User < ActiveRecord::Base belongs_to: category end belongs_to indicates the presence of a foreign key.
Step 2. Consider a table users created using SQL
CREATE TABLE users ( uid int(11), uname varchar(255), PRIMARY KEY(uid) ); Step 3. You can now perform the following actions u = User.new u.name = "Mike" puts p.name # "Mike"
CRUD operations:
All these methods are of active record and not of all ruby objects in general.
Create
Create method call will create and save a new record into the database:
car= Car.create(name: "Skoda", year: 2000)
New method call creates a new record but does not save it.
car = Car.new car.name = "Skoda" car.year=2000
A call to user.save will commit the record to the database
If you don’t save, primary key returns nil or new record returns true
Read
cars=Car.all car=Car.first skoda=Car.find_by(name: ‘Skoda’)
Update
To update a particular entry
car = User.find_by(name: 'Skoda') car.update(name: 'Skoda A1')
Destroy
user = User.find_by(name: 'Skoda') user.destroy
Once you destroy an object, you can’t modify/update it but you can access it.
Validation
You can validate the state of a model before it gets written into the database.
class Car < ActiveRecord::Base validates :name, presence: true end
You can check for presence, uniqueness etc. on the attributes
Data Mapper
Datamapper has the capability to use the same API for a variety of datastores. There are adapters for the usual RDBMS suspects, NoSQL stores, various file formats and even some popular web services. With DataMapper, we can define our mappings in our model. Our data-store can develop independently of our models using migrations. We just need to mention to the DataMapper where to look to support data-stores which we cannot manage ourselves. DataMapper only updates or creates properties that it is aware of. Hence it can be used in an Integration Database without any hassles. DataMapper is an Object Relational Mapper written in Ruby.
Key Features:
- fast
- thread-safe
- feature rich
CRUD Operations in DataMapper:
Create
The #create method can be used to create a new resourse with particular attributes.
user = User.create(:name => 'Michael', :inception => User.now)
If the creation was successful, #create will return the newly created DataMapper::Resource. If it failed, it will return a new resource that is initialized with the given attributes and possible default values declared for that resource, but that's not yet saved. To find out whether the creation was successful or not, we can use #saved? on the returned resource. If the record was successfully persisted, it returns true, else it returns false.
Save
We can also create a new instance of the model, update its properties and then save it to the data store. If the record was saved , true would be returned else it will return false.
user= User.new user.attributes = { :name => 'Michael', :inception => User.now } user.save
Read
DataMapper has methods which allow you to grab a single record by key, the first match to a set of conditions
user=User.get(1)
Update
We can also update a model's properties and save it with one method call. #update will return true if the record saves and false if the save fails, exactly like the #save method.
user.update(:name => 'Michael')
Destroy
To destroy a record, we simply call its #destroy method. It will return true or false depending if the record is successfully deleted or not.
user= User.get(2) user.destroy # => true
Validations
Validations can be done both manually and automatically.
Manual Validation
Much like a certain other Ruby ORM we can call validation methods directly by passing them a property name (or multiple property names) to validate against.
validates_length_of :name validates_length_of :name, :grade
Auto-Validations
By adding triggers to our property definitions we can both define and validate our classes properties.
require 'dm-validations' class User include DataMapper::Resource property :name, String # manual validation validates_length_of :name, :max => 30 # auto validations property :content, Text, :length => 100..500 end
Advantages
- Eager loading of child associations to avoid (N+1) queries
- Lazy loading of select properties, e.g., larger fields
- Query chaining, and not evaluating the query until absolutely necessary (using a lazy array implementation)
- An API not too heavily oriented to SQL databases
Sequel
Sequel was originally developed by Sharon Rosner and the first release was in March 2007. It is based on the active record pattern. Sequel, like ActiveRecord use the active record pattern of database access, supports associations and inheritance. But Sequel handles these features in a much more flexible manner.
Comparison Between active record and sequel:
Active Record Sequel belongs_to many_to_one has_one one_to_one has_many one_to_many has_and_belongs_to_many many_to_many
Sequel maps classes to tables and automatically creates accessor methods for the attributes in the table. For example, if we have a table names users with primary key user_id and an attribute names "user_name", the minimal model class is as follows:
class User < Sequel::Model end
The attribute accessors autogenerated are:
user = User.new user.user_name = "Vin"
Sequel's validation_class_methods plugin is modeled directly on ActiveRecord's validations, but the recommended approach is to use the validation_helpers plugin inside a validate instance method:
class User < Sequel::Model plugin :validation_helpers def validate super validates_presence [:name, :user_name] validates_unique [:name, :user_name] end end
CRUD operations in sequel
require "rubygems" require "sequel" # connect to an in-memory database DB = Sequel.sqlite # create a users table DB.create_table :users do primary_key :id String :name end
# create a dataset from the users table users = DB[:users] # populate the table users.insert(:name => 'abc') users.insert(:name => 'def') users.insert(:name => 'ghi')
# print out the number of records puts "User count: #{users.count}"
Key Features
- Thread safety, connection pooling
- Concise DSL for creating SQL queries and table schemas.
- Supports advanced database features like prepared statements, bound variables, stored procedures, savepoints and many more.
- A comprehensive ORM layer for mapping od database records to Ruby objects and handling associations.