CSC/ECE 517 Fall 2013/ch1 1w43 av

From Expertiza_Wiki
Jump to navigation Jump to search

OBJECT RELATIONAL MAPPING

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)<ref>http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2013/ch1_1d_zk</ref>

Overview

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

ORM features constitutes the following:<ref>http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2013/ch1_1d_zk</ref>

  • 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 allows 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.<ref>http://edgeguides.rubyonrails.org/active_record_basics.html</ref>

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 Category < 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 ActiveRecord 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

You can read the data in many ways. It can be used to find all or particular entries in a table.

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.<ref>http://datamapper.org/getting-started.html</ref>

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. <ref>http://sequel.rubyforge.org</ref>

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 of database records to Ruby objects and handling associations.

iBATIS

  • iBATISS is a persistence framework which automates the mapping between SQL databases and objects in Java, .NET, and Ruby on Rails.
  • It is a lightweight framework and persistence API good for persisting POJOs( Plain Old Java Objects).
  • It is what is known as a data mapper and maps the parameters and results between class attributes and columns of the database.<ref>http://www.tutorialspoint.com/ibatis‎</ref>

Advantages of IBATIS

Here are few advantages of using IBATIS:

  • Suppports Stored procedures: iBATIS encapsulates SQL in the form of stored procedures so that business logic is kept out of the database, and the application is easier to deploy and test, and is more portable.
  • Supports Inline SQL: No precompiler is needed, and you have full access to all of the features of SQL.
  • Supports Dynamic SQL: iBATIS provides features for dynamically building SQL queries based on parameters.
  • Supports O/RM: iBATIS supports many of the same features as an O/RM tool, such as lazy loading, join fetching, caching, runtime code generation, and inheritance.<ref>http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Spring_2013/ch1_1d_zk</ref>

Comparison of ORM Features

<ref>http://stackoverflow.com/questions/2414284/whats-the-significant-difference-between-active-record-and-data-mapper-based-or</ref>

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

Mapping

Maps an object to a record in the database. Maps an object with data but it need not be a record. Maps an object to a record in the database.

Migrations

Needs a predefined database or use migrations to generate the schema. Automigrations can generate the schema. Database structure can be manually created. Migrations are optional.

Read operations

It uses .find for search. It used .get data finder. It uses chains on datasets.


Advantages Of ORM

  • Object relation model tools enables us to model entities in accordance with the real business needs rather than adhering to the database structure. This is done using mapping between the logical business model and the physical storage model.
  • The varied services provided by Object Relation model allows the developers to focus more on the business logic rather than CRUD logic.
  • The ORM automatically refers to the updated structure for CRUD operations when the object definitions are updated. Thus, no different layers need to be modified manually since changes to the object model are in one place.
  • The object oriented query language provided by ORM enables the developers to focus on the object model rather than the database structure.
  • Object relationships can be navigated transparently. When one object is loaded, its related objects are automatically loaded. For instance, if a user object has been loaded and we want to access the user's posts, we can simply write user.posts and the posts object would be automatically loaded.
  • If multiple users update the data simultaneously, concurrency is maintained.
  • ORM enables cache management and hence the entities are loaded in the cache memory thereby reducing the load on the database.
  • ORM follows transaction management and its properties. <ref>http://blogs.msdn.com/b/gblock/archive/2006/10/26/ten-advantages-of-an-orm.aspx</ref>

References

<references />