CSC/ECE 517 Fall 2013/ch1 1w43 av: Difference between revisions
(→Read) |
|||
(3 intermediate revisions by the same user not shown) | |||
Line 72: | Line 72: | ||
PRIMARY KEY(uid) | PRIMARY KEY(uid) | ||
); | ); | ||
</pre> | |||
Step 3. You can now perform the following actions | Step 3. You can now perform the following actions | ||
<pre> | |||
u = User.new | u = User.new | ||
u.name = "Mike" | u.name = "Mike" | ||
Line 105: | Line 106: | ||
<pre> | <pre> | ||
cars=Car.all | cars=Car.all | ||
car=Car.first | car=Car.first | ||
skoda=Car.find_by(name: ‘Skoda’) | skoda=Car.find_by(name: ‘Skoda’) | ||
</pre> | </pre> | ||
Line 117: | Line 115: | ||
<pre> | <pre> | ||
car = User.find_by(name: 'Skoda') | car = User.find_by(name: 'Skoda') | ||
car.update(name: 'Skoda A1') | car.update(name: 'Skoda A1') | ||
</pre> | </pre> | ||
Line 126: | Line 122: | ||
<pre> | <pre> | ||
user = User.find_by(name: 'Skoda') | user = User.find_by(name: 'Skoda') | ||
user.destroy | user.destroy | ||
</pre> | </pre> | ||
Once you destroy an object, you can’t modify/update it but you can access it. | Once you destroy an object, you can’t modify/update it but you can access it. |
Latest revision as of 17:37, 7 October 2013
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
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 />