CSC/ECE 517 Fall 2010/ch2 2a aa
[Language extensions for ORM]
Introduction to Object Relational Mapping.
Object Relational Mapping is a technique of mapping the solution entities of an object oriented system, objects [1]to relational database [2] tables. This technique came into existence as an answer to the problem of lack of persistence of objects across session in Object Oriented Programming Systems [3]. For instance in a software solution to manage the order and inventory systems of a company, the objects that are part of the systems e.g orders, customers, must be accessible even if the system was temporarily shut down for a while. ORM [4] helps in achieving this very essential requirement by bringing the database into the picture, more specifically bringing the RDBMS into the picture.
Why ORM, why not another solution?
The answer to this is quite an obvious one. ORM brings to the table something(s) that another solution hasn’t done so far. These “something(s)” that ORM contributes are listed below:
- Alleviates the problem that hinders a transition from one database provider to another database vendor or even another database product.
- Enables to perform most of the database operations (mainly CRUD[5]) without having to write any SQL [6] statements, thereby permitting a shift from one SQL dialect to another. This also allows the software solutions to focus more on the actual problem being solved rather that performing supplementary functions extensively.
Flavors of ORM solutions.
The term ORM is a very generic name for the class of solutions. Typically, ORM support in object oriented languages comes in two flavors; one that comes in separate packages which can be imported into our application, the other is the variety that comes incorporated into a language. When there is an option of choosing among the two flavors, the solution that come incorporated into the language is preferred. This choice may be quite an obvious one depending on the language that is being considered. Though the difference between the two might not be that apparent in the outset, the reason for this predilection towards the language incorporate solution over the other has mainly to do with design paradigm of the modern day software development of “convention over configuration”[7]. This paradigm emphasizes on the development by convention rather than development by configuration. The fact that the solution involving external packages and libraries involve a lot of configuration files which play the instructing role. In the language incorporated solution, such a problem doesn’t arise as the involvement of configuration files in the entire system itself is scanty. In the following sections we will take a look at two of the preferred language incorporated solutions.
ORM implementation in specific languages.
In this section, we will look at the language specific ORM examples illustrating the relation between creation of classes and tables, objects and rows, attributes and columns; and also examples for performing basic CRUD operations for two specific Object Oriented languages.
Groovy, Grails and GROM:
Creating classes and tables:
Classes, when created using the create-domain-class, also create the table of the same name as the class (not the plural). For example,
grails create-domain-class Assignment
running the above command would create an empty class named Assignment and also create a table named Assignment in the database. Attributes to this class may be added in a fashion similar to the one followed in java. The attributes that are created in-turn gets automatically mapped to the columns in the table “Assignment”.
We may want to define the Assignment class as follows
class Assignment { String title Date dueDate String weightage_on_final_grade }
Having objects defined within a class would facilitate in achieving association between classes.
Basic CRUD:
- Creating objects also creates rows. This is done as illustrated below:
def a = new Assignment (title:"WikiTextChapter", dueDate:date, weightage_on_final_grade:3) a.save()
The above statements would create a new Assignment object and also create a row in the Assignment table. The save method above may be considered analogous to a commit statement that may be used in SQL.
- Reading objects from the database. This can be done as in the below example.
def a = Assignment.get(1)
In the above statement, the parameter 1 passed to the get method is an identifier for the object. When an object is created in the database, an id is created transparently by the language specifics. Apart from the get method, other ways of fetching objects from database would involve use of methods such as list(), findBy<attributeName>() few among the many other methods that is on offer.
- Updating objects. This is achieved by updating the necessary attribute of an object and saving or committing the changes back to the database. This is illustrated in the below example.
def a = Assignment.get(1) a. weightage_on_final_grade =5 a.save()
- Deleting objects. To perform a delete, we must first get an object and then call the delete method on that object. This is illustrated in the below example.
def a = Assignment.get(1) a.delete()
PHP ActiveRecord:
Creating classes and tables:
Tables corresponding to classes can be created by
classes extending the ActiveRecord\Model class. class Assignment extends ActiveRecord\Model { }
Basic CRUD:
- Creating objects also creates rows. This can be done by as shown below.
$a = new Assignment(); $a-> title=’ WikiTextChapter’; $a->save();
- Reading objects from database. Objects can be read from the database as illustrated in the below example.
$a = Assignment::find(1);
- Apart from the get method, other ways of fetching objects from database would involve use of methods such as findBy<attributeName>() few among the many other methods that is on offer.
- Updating objects. For this to be done, we need to find a record first and then change one of its attributes and finally commit the changes. This is illustrated below:
$a = Assignment::find(1); $a->title = 'NewWikiTextChapter’'; $a->save();
- Deleting objects. For this to be done, we need to find a record first and then call the delete method on the object.
$a = Assignment::find(1); $a->delete();
- This is similar to ActiveRecord in Ruby, so we will not explicitly deal with ORM in Ruby.
Language support for ORM.
To incorporate ORM into a language, the usual approach, is to implement the ActiveRecord Design Pattern [8]. This approach considers persistence as a responsibility of the object rather than as a service. Following this approach, would hence expect the objects themselves implement methods to support database operations and like in the object oriented world the objects are expected to be able to manage themselves. Following the object oriented paradigm and adopting a modular approach the responsibility of implementing the methods facilitating the database operations are implemented by a class which is inherited by all other classes whose objects have to persist across sessions. The methods to support database operations include methods to create tables, create rows in the table when objects of a class are created; methods to read objects from the table; methods that facilitate updating the objects and finally methods to delete the objects. Apart from this basic CRUD functionality any extra functionality would always be welcome.
References and Further Reading
- one Very informative and a nice place to start. http://www.slideshare.net/hominhchuc/grails-docs-presentation
- two Insight into impedance mismatch. http://www.agiledata.org/essays/impedanceMismatch.html
- three List of object-relational mapping software http://en.wikipedia.org/wiki/List_of_object-relational_mapping_software
- Active Record Design Pattern - Domain Driven Design and Domain Layer - Object Persistence. http://davidhayden.com/blog/dave/archive/2006/06/10/2984.aspx
- Grails home page. http://grails.org/
- ORM in php: php.active record http://www.phpactiverecord.org/
- Active Record Design Pattern http://en.wikipedia.org/wiki/Active_record_pattern