CSC/ECE 517 Fall 2010/ch3 3j KS: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
 
(42 intermediate revisions by 2 users not shown)
Line 1: Line 1:
='''Object-relational Mapping for Ruby'''=
=Object-relational Mapping for Ruby=


__TOC__
__TOC__
Line 5: Line 5:
=Introduction=
=Introduction=


[http://en.wikipedia.org/wiki/Object-relational_mapping 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 in addition to ActiveRecord, the ORM layer supplied with Rails.
[http://en.wikipedia.org/wiki/Object-relational_mapping 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.  Other products related to Ruby ORM were excluded from this comparison if their scope was limited to a subset of ORM functionality or if support for the product has waned in recent years (eg RBatis, the port of Apache iBatis ORM to Ruby).


=Overview=
=Overview=
Line 26: Line 26:
[[Image:3j_ks_pic1.jpg]]
[[Image:3j_ks_pic1.jpg]]


When applied to Ruby, implementations of ORM often leverage the language’s [http://en.wikipedia.org/wiki/Metaprogramming metaprogramming] strengths to create intuitive application-specific methods and otherwise extend classes to support database functionality.


When applied to Ruby, implementations of ORM often leverage the language’s [http://en.wikipedia.org/wiki/Metaprogramming metaprogramming] strengths to create intuitive application-specific methods and otherwise extend classes to support database functionality.
=ActiveRecord=


Perhaps add section w/ examples of typical Ruby ORM techniques here else just cover in each product…
[http://ar.rubyonrails.org/ ActiveRecord], originally created by David Heinemeier and released in 2003, became the de-facto ORM for Ruby since it was integrated in the widely-used Rails framework, however alternate ORMs for Ruby have been developed and Rails 3.x is ORM independent. ActiveRecord is an implementation of the active record design pattern, where a table is wrapped into a class and this class implements accessor methods for each column in the table.


=Comparison of ORM products for Ruby=
To create a table, ActiveRecord makes use of a migration class rather than including table definition in the actual class being modeled.  As an example, the following code creates a table ‘’users’’ to store a collection of class ‘’User’’ objects:
<pre>
class CreateUsers < ActiveRecord::Migration
  def self.up
    create_table :users do |t|
      t.string :name
      t.string :email
      t.string :age


==''' ActiveRecord '''==
      t.timestamps    # add creation and modification timestamps
    end
  end


[http://ar.rubyonrails.org/ ActiveRecord], originally created by David Heinemeier and released in 2003, became the de-facto ORM for Ruby since it was integrated in the widely-used Rails framework, however alternate ORMs for Ruby have been developed and Rails 3.x is ORM independent. ActiveRecord is an implementation of the active record design pattern, where a table is wrapped into a class and this class implements accessor methods for each column in the table. [http://en.wikipedia.org/wiki/Active_record_pattern]
  def self.down        # undo the table creation
    drop_table :users
  end
end
</pre>


ActiveRecord uses a single table inheritance scheme, which trades off some storage efficiency for simplicity in the database designAdd a pic for to describe…
Note in the preceeding example, that the ActiveRecord’s migration scheme provides a means for backing out changes via the ‘’self.down’’ methodIn addition, a table key ‘’id’’ is added to the new table without explicit definition and record creation and modification timestamps are included via the ‘’timestamps’’ method provided by ActiveRecord. 


ActiveRecord manages associations between table elements and provides the means to define such associations in the model definition.  For example, the User class shown below defines a ‘’to_many’’ association with both the cheers and posts tables.  Also note ActiveRecord’s integrated support for validation of table information when attempting an update.
ActiveRecord manages associations between table elements and provides the means to define such associations in the model definition.  For example, the ‘’User’’ class shown below defines a ‘’to_many’’ association with both the cheers and posts tables.  Also note ActiveRecord’s integrated support for validation of table information when attempting an update.


<pre>
<pre>
class User < ActiveRecord::Base
class User < ActiveRecord::Base
 
   has_many :cheers
   has_many :cheers
   has_many :posts
   has_many :posts
    
    
   validates_presence_of :name
   validates_presence_of :name
  validates_presence_of :age
   validates_uniqueness_of :name
   validates_uniqueness_of :name
   validates_length_of :name, :within => 3..20
   validates_length_of :name, :within => 3..20
end
end
</pre>
</pre>
While ActiveRecord provides the flexibility to create more sophisticated table relationships to represent class hierarchy, its base scheme is a single table inheritance, which trades some storage efficiency for simplicity in the database design. The following figure illustrates this concept of simplicity over efficiency. 
[[Image:3j_ks_pic2.jpg]]


'''Pros''' -
'''Pros''' -
* Integrated with Rails development framework
* Integrated with popular Rails development framework
* Dynamically created database search methods (eg User.find_by_address) ease db queries and make queries database syntax independent
* Dynamically created database search methods (eg: User.find_by_address) ease db queries and make queries database syntax independent
* DB creation/management using the migrate scheme provides a means for backing out unwanted table changes
'''Cons''' -
'''Cons''' -
* DB creation/management is decoupled from the model, requiring a separate utility (rake/migrate) that must be kept in sync with application
* DB creation/management is decoupled from the model, requiring a separate utility (rake/migrate) that must be kept in sync with application


 
=Sequel=
 
=='''Sequel'''==  


[http://sequel.rubyforge.org Sequel] was originally developed by Sharon Rosner and the first release was in March 2007. It is based on the active record pattern. Sequel and Active record share a lot of common features , for example association and inheritance. But Sequel handles these features in a much more flexible manner. Currently Sequel is at version 3.16.0. Initially Sequel was had three core modules - sequel, sequel_core and sequel_model.Starting from version 1.4 , sequel and sequel_model were merged. Sequel handles validations using a validation plug-in and helpers.
[http://sequel.rubyforge.org Sequel] was originally developed by Sharon Rosner and the first release was in March 2007. It is based on the active record pattern. Sequel and Active record share a lot of common features , for example association and inheritance. But Sequel handles these features in a much more flexible manner. Currently Sequel is at version 3.16.0. Initially Sequel was had three core modules - sequel, sequel_core and sequel_model.Starting from version 1.4 , sequel and sequel_model were merged. Sequel handles validations using a validation plug-in and helpers.
Some of the key features of sequel are,
* Connection Pooling
* Thread Safety
* Eager Loading / Lazy Loading
* Model Caching


<pre>
<pre>
Line 77: Line 88:
       primary_key :id
       primary_key :id
       String :name
       String :name
       String :password }
       String :age
      String :email}
   end
   end
   def down
   def down
Line 85: Line 97:
</pre>
</pre>


==''' DataMapper'''==
Sequel supports associations and validations similar to ActiveRecord. The following example shows how validations and associations can be enforced int he User table that has been created above. It enforces one to many relationship between the user table and the cheers , posts tables. It also validates for the presence , uniqueness and the length of the attribute '''name'''.
http://www.gelens.org/2007/12/13/ruby_orm_datamapper/
 
Ruby ORM: DataMapper
<pre>
There is a relative new ORM (Object Relational Mapper) for Ruby called “DataMapper”. Its goal is to create a fast, feature rich and thread-safe(!) ORM. DataMapper can be used standalone or as plugin for example Rails or Merb.  
class User < Sequel::Model
Finally some competition in the Ruby ORM world. Rails’ ActiveRecord is no longer the only usable production ORM. DataMapper’s developers made some radical different fundamental design decisions regarding to migrations and property declarations. Property declarations are now done in the Model itself and not in separate “migration”-files. Which is more elegant in my opinion.
  one_to_many :cheers
Lately DataMapper is growing fast, it gets more attention and its feature list gets longer and is already superior to AR in terms of speed. A few weeks ago I started a new project using the new ruby framework Merb. Merb is also thread-safe and is in combination with DataMapper a really cool framework. By the way, did you know Rails is not thread-safe? Kinda sucky for a web framework to handle only one connection at a time. That’s the reason why people use multiple Mongrel servers when deploying Rails application. Not everyone I know seems to realize that. The bad thing is, there is NO plan to make it thread-safe :-/.
  one_to_many :posts
[http://blog.mattwynne.net/2008/05/23/datamapper-a-better-orm-for-ruby/]
 
DataMapper: A Better ORM for Ruby
  validates_presence [:name, :age]
One of the things that’s always irritated my about rails’ ActiveRecord framework is the way that the domain model lives in the database.Don’t get me wrong: it’s very clever, and a great showcase for ruby’s metaprogramming features, which will blow average C# / Java mind the mind when they first see it.
  validates_unique(:name)
In rails, you build a database of your domain model, and create empty classes with the names of the domain entities (conventionally the singular of a database table name) which inherit from ActiveRecord. ActiveRecord then looks at your database, and using the magic of metaprogramming, hydrates your object with a bunch of properties that map to the database fields.
  validates_length_range 3..20, :name
But I prefer to write my models in the code, and if you do too, you might want to take a look at DataMapper.
end
</pre>
 
Some of the key features of sequel are,
* Connection Pooling
* Thread Safety
* [http://wiki.rubyonrails.org/howtos/db-relationships/eager-loading Eager Loading] / Lazy Loading
* Model Caching
 
=DataMapper=
 
[http://datamapper.org/ DataMapper] is an open source ORM for Ruby originally developed by Sam Smoot and first released in 2007. DataMapper provides a very flexible mapping API which allows creation of adapters to a wide variety of datastores beyond traditional SQL-based relational databases – DataMapper adapters have been created to non-standard sources such as the Salesforce API and even Google Video.
 
Unlike ActiveRecord and Sequel, DataMapper does not rely on a migration scheme to create and manage DB tables. Instead, DataMapper allows table definition as part of the model class definition which keeps the model definition contained to a single file, thus minimizing the effort required to keep the database and model definitions in sync. When required, DataMapper can also support a migration methodology similar to other ORMs.
Example of table definition in the model:
<pre>
class User
  include DataMapper::Resource
 
  property :id,        Serial    # key
  property :name,      String, :required => true, :unique => true   
  property :age,        String, :required => true, :length => 3..20
  property :email,      String
 
  has n, :posts          # one to many association
  has n, :cheers          # one to many association
end
</pre>
 
Notice that in the example above , ":required = true" is an example for Auto Validation. Unlike ActiveRecord and Sequel, DataMapper supports auto validations , i.e. these in turn call the validation helpers to enforce basic validations such as length, uniqueness, format, presence etc.
 
Some of the key features of DataMapper are:
* API supports a wide variety of databases, including non SQL types
* Thread Safety
* [http://wiki.rubyonrails.org/howtos/db-relationships/eager-loading Eager Loading] of child associations
* Lazy loading


=Comparison of ORM Features=
=Comparison of ORM Features=


{| class="wikitable sortable" border="1" style="font-size: 100%; text-align: left; width: auto;"
{|cellspacing="0" border="1"
|-
!style="width:10%"|Features  
! ''' Features '''
!style="width:30%"|ActiveRecord
! ''' ActiveRecord '''
!style="width:30%"|Sequel
! ''' Sequel '''
!style="width:30%"|DataMapper
! ''' DataMapper '''
|-
|-
! '''Databases'''
! <p align="left"> Databases </p>
| MySQL, PostgreSQL, SQLite, Oracle, SQLServer, and DB2
| MySQL, PostgreSQL, SQLite, Oracle, SQLServer, and DB2
| ADO, DataObjects, DB2, DBI, Firebird, Informix, JDBC, MySQL, ODBC, OpenBase, Oracle, PostgreSQL and SQLite3
| ADO, DataObjects, DB2, DBI, Firebird, Informix, JDBC, MySQL, ODBC, OpenBase, Oracle, PostgreSQL and SQLite3
| yes
| SQLite, MySQL, PostgreSQL, Oracle, MongoDB, SimpleDB, many others, including CouchDB, Apache Solr, Google Data API
|-
|-
! '''Migrations'''
! <p align="left"> Migrations </p>
| Yes
| Yes
| Yes
| Yes
| yes
| Yes, but optional
|-
|-
! '''EagerLoading'''
! <p align="left"> EagerLoading </p>
| yes
| Supported by scanning the SQL fragments
| yes
| Supported using eager (preloading) and eager_graph (joins)
| yes
| Strategic Eager Loading and by using :summary
|-
|-
! '''Flexible Overriding'''
! <p align="left"> Flexible Overriding </p>
| yes
| No. Overriding is done using alias methods.
| yes
| Using methods and by calling 'super'
| yes
| Using methods
|-
|-
! '''Dynamic Finders'''
! <p align="left"> Dynamic Finders </p>
| yes
| Yes. Uses 'Method Missing'
| yes
| No. Alternative is to use <Model>.FindOrCreate(:name=>"John")
| yes
| Yes. Using the dm_ar_finders plugin
|}
|}


<pre>
<br />
Code example
</pre>


=Conclusion=
=Further Reading=
Ruby ORM bla.
To get more information on ORM and the different type of ORM's available for Ruby , please look into the [http://pg-server.csc.ncsu.edu/mediawiki/index.php/CSC/ECE_517_Fall_2007/wiki2_2_22, Object-relational mapping Fall 2007] wiki.


<br />
=Future Work=
More work can be done in the area of comparison between the different ORMs available for Ruby, especially a more detailed feature-by-feature comparison that includes performance differences between the ORMs. We came across one cool website which has a detailed ORM comparison for .Net [http://ormbattle.net/ ORMBattle.Net]. Something similar would be really helpful for Ruby, but due to the time contraints of this project we were not able to work on these areas.


=References=
=References=


[1] [http://ruby-doc.org/ Ruby language]
# [http://en.wikipedia.org/wiki/Object-relational_mapping Wikipedia, Object-relational mapping (ORM)]
 
# [http://ar.rubyonrails.org/ ActiveRecord]
[2] Fowler, C., The Ruby FAQ, www.rubygarden.org/faq
# [http://en.wikipedia.org/wiki/Active_record_pattern Wikipedia Active record pattern]
 
# [http://sequel.rubyforge.org/ Sequel]
[3] , Active Record — Object-relation mapping put on rails, http://ar.rubyonrails.org/
# [http://jeremyevans-pres.heroku.com/mwrc2009_presentation.html  Sequel Presentation - By Jeremy Evans]
 
# [http://merbist.com/2008/09/29/write-your-own-custom-datamapper-adapter/  Merbist blog on custom DM adapters - By Matt Aimonetti]
==External Links==
# [http://en.wikipedia.org/wiki/Datamapper DataMapper]
 
# [http://pg-server.csc.ncsu.edu/mediawiki/index.php/CSC/ECE_517_Fall_2007/wiki2_2_22 Object-Relational Mapping Fall 2007]
#[http://wxruby.rubyforge.org/wiki/wiki.pl WxRuby]
# [http://ormbattle.net/ ORMBattle.Net]
#[http://www.activestate.com/activetcl ActiveTcl for Windows]
# [http://wiki.rubyonrails.org/howtos/db-relationships/eager-loading Eager-loading description on Rails Wiki]

Latest revision as of 18:16, 15 October 2010

Object-relational Mapping for Ruby

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. Other products related to Ruby ORM were excluded from this comparison if their scope was limited to a subset of ORM functionality or if support for the product has waned in recent years (eg RBatis, the port of Apache iBatis ORM to Ruby).

Overview

Object-relational Mapping (ORM) frameworks unburden the designer of the complex translation between database and object space.

Typical ORM features:

  • Automatic mapping from classes to database tables
    • Class instance variables to database columns
    • Class instances to table rows
  • Aggregation and association relationships between mapped classes are managed
    • Example, :has_many, :belongs_to associations in ActiveRecord
    • Inheritance cases are mapped to tables
  • Validation of data prior to table storage
  • Class extensions to enable search, as well as creation, read, update, and deletion (CRUD) of instances/records
  • Usually abstracts the database from program space in such a way that alternate database types can be easily chosen (SQLite, Oracle, etc)

The diagram below depicts a simple mapping of an object to a database table….

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.

ActiveRecord

ActiveRecord, originally created by David Heinemeier and released in 2003, became the de-facto ORM for Ruby since it was integrated in the widely-used Rails framework, however alternate ORMs for Ruby have been developed and Rails 3.x is ORM independent. ActiveRecord is an implementation of the active record design pattern, where a table is wrapped into a class and this class implements accessor methods for each column in the table.

To create a table, ActiveRecord makes use of a migration class rather than including table definition in the actual class being modeled. As an example, the following code creates a table ‘’users’’ to store a collection of class ‘’User’’ objects:

class CreateUsers < ActiveRecord::Migration
  def self.up
    create_table :users do |t|
      t.string :name
      t.string :email
      t.string :age

      t.timestamps     # add creation and modification timestamps
    end
  end

  def self.down        # undo the table creation
    drop_table :users
  end
end

Note in the preceeding example, that the ActiveRecord’s migration scheme provides a means for backing out changes via the ‘’self.down’’ method. In addition, a table key ‘’id’’ is added to the new table without explicit definition and record creation and modification timestamps are included via the ‘’timestamps’’ method provided by ActiveRecord.

ActiveRecord manages associations between table elements and provides the means to define such associations in the model definition. For example, the ‘’User’’ class shown below defines a ‘’to_many’’ association with both the cheers and posts tables. Also note ActiveRecord’s integrated support for validation of table information when attempting an update.

class User < ActiveRecord::Base
  has_many :cheers
  has_many :posts
  
  validates_presence_of :name
  validates_presence_of :age
  validates_uniqueness_of :name
  validates_length_of :name, :within => 3..20
end

While ActiveRecord provides the flexibility to create more sophisticated table relationships to represent class hierarchy, its base scheme is a single table inheritance, which trades some storage efficiency for simplicity in the database design. The following figure illustrates this concept of simplicity over efficiency.

Pros -

  • Integrated with popular Rails development framework
  • Dynamically created database search methods (eg: User.find_by_address) ease db queries and make queries database syntax independent
  • DB creation/management using the migrate scheme provides a means for backing out unwanted table changes

Cons -

  • DB creation/management is decoupled from the model, requiring a separate utility (rake/migrate) that must be kept in sync with application

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 and Active record share a lot of common features , for example association and inheritance. But Sequel handles these features in a much more flexible manner. Currently Sequel is at version 3.16.0. Initially Sequel was had three core modules - sequel, sequel_core and sequel_model.Starting from version 1.4 , sequel and sequel_model were merged. Sequel handles validations using a validation plug-in and helpers.

class CreateUser < Sequel::Migration
  def up
    create_table(:user) {
      primary_key :id
      String :name
      String :age
      String :email}
  end
  def down
    drop_table(:user)
  end
end # CreateUser.apply(DB, :up)

Sequel supports associations and validations similar to ActiveRecord. The following example shows how validations and associations can be enforced int he User table that has been created above. It enforces one to many relationship between the user table and the cheers , posts tables. It also validates for the presence , uniqueness and the length of the attribute name.

class User < Sequel::Model
  one_to_many :cheers
  one_to_many :posts
  
  validates_presence [:name, :age]
  validates_unique(:name)
  validates_length_range 3..20, :name
end

Some of the key features of sequel are,

  • Connection Pooling
  • Thread Safety
  • Eager Loading / Lazy Loading
  • Model Caching

DataMapper

DataMapper is an open source ORM for Ruby originally developed by Sam Smoot and first released in 2007. DataMapper provides a very flexible mapping API which allows creation of adapters to a wide variety of datastores beyond traditional SQL-based relational databases – DataMapper adapters have been created to non-standard sources such as the Salesforce API and even Google Video.

Unlike ActiveRecord and Sequel, DataMapper does not rely on a migration scheme to create and manage DB tables. Instead, DataMapper allows table definition as part of the model class definition which keeps the model definition contained to a single file, thus minimizing the effort required to keep the database and model definitions in sync. When required, DataMapper can also support a migration methodology similar to other ORMs.

Example of table definition in the model:

class User
  include DataMapper::Resource

  property :id,         Serial    # key
  property :name,       String, :required => true, :unique => true     
  property :age,        String, :required => true, :length => 3..20 
  property :email,      String 
  
  has n, :posts          # one to many association
  has n, :cheers          # one to many association
end

Notice that in the example above , ":required = true" is an example for Auto Validation. Unlike ActiveRecord and Sequel, DataMapper supports auto validations , i.e. these in turn call the validation helpers to enforce basic validations such as length, uniqueness, format, presence etc.

Some of the key features of DataMapper are:

  • API supports a wide variety of databases, including non SQL types
  • Thread Safety
  • Eager Loading of child associations
  • Lazy loading

Comparison of ORM Features

Features ActiveRecord Sequel DataMapper

Databases

MySQL, PostgreSQL, SQLite, Oracle, SQLServer, and DB2 ADO, DataObjects, DB2, DBI, Firebird, Informix, JDBC, MySQL, ODBC, OpenBase, Oracle, PostgreSQL and SQLite3 SQLite, MySQL, PostgreSQL, Oracle, MongoDB, SimpleDB, many others, including CouchDB, Apache Solr, Google Data API

Migrations

Yes Yes Yes, but optional

EagerLoading

Supported by scanning the SQL fragments Supported using eager (preloading) and eager_graph (joins) Strategic Eager Loading and by using :summary

Flexible Overriding

No. Overriding is done using alias methods. Using methods and by calling 'super' Using methods

Dynamic Finders

Yes. Uses 'Method Missing' No. Alternative is to use <Model>.FindOrCreate(:name=>"John") Yes. Using the dm_ar_finders plugin


Further Reading

To get more information on ORM and the different type of ORM's available for Ruby , please look into the Object-relational mapping Fall 2007 wiki.

Future Work

More work can be done in the area of comparison between the different ORMs available for Ruby, especially a more detailed feature-by-feature comparison that includes performance differences between the ORMs. We came across one cool website which has a detailed ORM comparison for .Net ORMBattle.Net. Something similar would be really helpful for Ruby, but due to the time contraints of this project we were not able to work on these areas.

References

  1. Wikipedia, Object-relational mapping (ORM)
  2. ActiveRecord
  3. Wikipedia Active record pattern
  4. Sequel
  5. Sequel Presentation - By Jeremy Evans
  6. Merbist blog on custom DM adapters - By Matt Aimonetti
  7. DataMapper
  8. Object-Relational Mapping Fall 2007
  9. ORMBattle.Net
  10. Eager-loading description on Rails Wiki