CSC/ECE 517 Fall 2012/ch1 1w10 pk: Difference between revisions
(→Django) |
|||
Line 215: | Line 215: | ||
</pre> | </pre> | ||
As you saw in some of the examples above, 2 of the 4 language extensions require external tools to generate the hooks in to the language. | As you saw in some of the examples above, 2 of the 4 language extensions require external tools to generate the hooks in to the language. | ||
==Conclusion== | ==Conclusion== |
Revision as of 20:41, 12 September 2012
Introduction
In the previous article for which the link does not exist yet, we learn that metaprogramming is where the computer code interacts with other programs as data and performs many of these interactions at compile time rather than runtime. This built-in interaction allows the programmers to take advantage of these capabilities and focus their time on the rest of their program logic instead of the details of some of the lower level coding. In this article, we will take a closer look at one of the styles of metaprogramming referred to as language extensions for object-relational mapping through examples and some comparisons of language extensions and tools.
Object-Relational Mapping
Object-Relational Mapping (ORM) is a methodology for managing data between object oriented systems and relational databases. The premise of the concept is to provide a universal method to access data in a database. This is beneficial for all programming languages that can use objects to store and retrieve data from the database. There are many languages that are using ORM as a technique to manage database data. In the rest of the article, we will discuss ORM and some of the languages in use today.
Language Extensions
Language extensions for ORM have often been traditionally classified as design patterns or software tools used to perform basic create, read, update and delete (C.R.U.D.) operations on relational databases, that is, until recent new approaches such as ActiveRecord have grown in popularity. ActiveRecord is not just a design pattern it is an increase of function to the active record pattern approach by adding inheritance and associations. Examining ActiveRecord and other language extensions will allow for comparisons of the ease of programming using these language extensions verses the conventional database oriented systems approach.
Ruby and ActiveRecord
All too often programmers are faced with the challenge of persisting objects from their program into a datastore. Custom code is created for this purpose that can be complex or difficult for others to understand as well as not seem natural. Applications that are designed to persist data have the need to know how the objects correspond to the information stored in these database tables. Ruby on Rails, first released in 2005, is able to provide a uniform method to help resolve these complicated issues without sacrificing function or knowledge of these objects by using ActiveRecord (AR). AR is a persistence engine that comes as part of Ruby on Rails. "It creates a 'persistable' domain model from business objects and database tables, where logic and data are presented as a unified package" 3. AR is admired for its simplistic and elegant approach of removing these levels of complexity. It allows for a 'pluggable' solution to many different popular databases available today to include: MySQL, SQLite, SQL Server, PostgreSQL, and Oracle.
ActiveRecord uses a Single Table Inheritance to allow for inheritance capabilities and provides a set of macros for association relationships between classes of objects, such as belongs_to, has_one, has_many, etc. AR is not only a component of the Model view-controller (MVC) for Ruby on Rails but it is also a standalone ORM package for Ruby itself. Ruby, Ruby on Rails, and ActiveRecord continue to grow in popularity due to not only the curiosity of programmers but their ability to improve function and feature sets while maintaining the initial intent of the language, "trying to make Ruby natural, not simple" -- Yukihiro “matz” Matsumoto 8. Other languages have been able to learn from AR and have tried to add this capability for themselves. Let’s take a closer look at some other implementations that attempts to duplicate AR’s elegance.
Other Examples of Language Extensions
ADO.NET Entity Framework
ADO.NET Entity Framework, Microsoft's ORM, part of .NET 4.0 was first developed in 2008. The Entity Framework tries to remove ORM mismatches that often plague conventional database oriented programs by using an Entity data model (EDM) and an Entity-Relationship data model to define the Relationships associated to each Entity. The EDM consists of a schema and a mapping specification. The schema defines the data types from the entities and the mapping provides the connections between the database scheme and the conceptual scheme. The Entity Framework has its own version of a query language called Entity SQL which continues to focus only on the conceptual entities and relationships as opposed to the actual database. It works with many popular databases available today to include: MySQL, SQLite, SQL Server, PostgreSQL, and Oracle.
Django
Python, presents an interesting case because it is an extremely similar language to Ruby in syntax and somewhat in philosophy. Django, is an ORM included in Django open source framework for Python. It follows a MVC architectural pattern and was originally released in 2005 with the primary goal of making complex, database driven websites easier to create and maintain. Instilled in its principles are emphasis on loose coupling, rapid development, don’t repeat yourself, and reusability (a.k.a. less code). The basis of its design is to encapsulate objects just like the ActiveRecord design pattern in models so that all the information needed can be stored in the model and knowledge of the database is not exposed. Django can essentially be considered the equivalent to Rails for Ruby.
Enterprise Objects Framework
Lastly we will introduce Enterprise Objects Framework (EOF), Mac OS X/Java, part of Apple WebObjects. EOF is the oldest of the bunch, introduced in 1994 for a product call NeXTSTEP. It was indented to eliminate the interaction with the relational database and the Java or Objective-C objects. EOF was later integrated into WebObjects. An EOFModel contains the mappings from the database to the classes, class attributes, and objects. EOF also incorporates inheritance into its feature set to allow a more object oriented approach using Enterprise Objects to reflect the hierarchy. EOF uses Java Database Connectivity (JDBC) and Java Naming and Directory Interface (JNDI) to talk to databases that support that, such as Oracle, DB2, and MySQL.
Java's Hibernate
Java is one of the most popular programming languages in existence today, and it therefore follows that there are many different options when it comes to ActiveRecord extensions to the language. One of the more popular extensions in use is Hibernate, an ORM solution for Java. Compared to the other languages presented here, Java is arguably the most involved from a developer’s perspective. By this, I mean that because it is strictly typed, compiled to byte code, and in general written at a lower level it is not always as straightforward and forgiving as the others. Keeping this in mind, we will try and gauge if the effort to set up and use Hibernate in a Java environment follows this same paradigm.
One of the first things that Hibernate uses for any interactions is a Session Factory class which is designed as a class factory to return the current Hibernate session object and ensure that only one instance of the session be issued per thread. Without listing the actual code of the Session Factory the code basically allows for getting the session object, opening the session for use, and closing the session after use.
Unlike some of the other languages the tables inside the database must be created by hand outside of Hibernate. This can be done using a specific SQL tool or using Java code that executes SQL code directly. This is a prime example of the additional knowledge a developer must have to correctly create a hibernate project. A developer must know that each object type must have its own table and that the fields within the table must correspond to the types of the object’s member variables.
Based on the tables created, classes must then be created with the member variables and setters/getters associated with the field types created in the database. For example, if the database table contains a field 'name' which is of type varchar and limited to 255 characters, the setter/getter must be of type String and the coder (if they wish) may limit the entry in the setter to 255 characters.
The next step is to create a Hibernate configuration file which essentially defines the database connection including the url, username, database type, password, etc. After this, the developer must explicitly tell Hibernate the relationships between the member variables of the class and the fields of the database with either an xml file or using Java annotations inside of the class. This is yet another example of the extra effort that has to be taken by the developer, but which also gives the developer great power and flexibility to name the fields and member variables different things.
Finally code can be written to create objects and write them to the database using the session object. The following snippet is an example of using the session object to write an object to the database.
Person p = new Person(); p.setFirstName(“John”); p.setLastName(“Doe”); Transaction tx = null; Session s1 = SessionFactory.getInstance().getCurrentSession(); try { tx = session.beginTransaction(); s1.save(p); tx.commit(); } catch(RuntimeException e) { tx.rollback(); }
There is no question that the set up effort involved in getting a Hibernate project going is substantially more than in ActiveRecord for Rails. The actual code to create and manipulate the objects is approximately the same between the two languages. This is clearly a case where more power is given to the developer but it is not without cost, which in this case is a fairly complex and involved list of set up steps.
JazzRecord for JavaScript
JavaScript presents another good case study for the use of ORM and ActiveRecord in application development. For one, JavaScript, like Python and Ruby, is loosely typed which can make dealing with the strictness of database typing an interesting challenge for these languages. Secondly, JazzRecord was modeled specifically after ActiveRecord in Ruby but does have its own differences.
Declaring a model in JazzRecord is very similar to ActiveRecord in structure, where the types of each of the fields must be explicitly identified so that the correct table can be created.
var Songs = new JazzRecord.Model({ table: "songs", columns: { title: "text", artist: "text" } });
Like ActiveRecord, retrieving objects from the database is effortless and very transparent. Here is an example of querying a few objects and then using those objects.
var song1 = Songs.findBy(“title”, “Purple Haze”); var song2 = Songs.findBy(“title”, “Stairway to Heaven”); var sameArtist = (song1.artist == song2.artist); song2.artist = “NewArtist”; song2.save();
The JazzRecord team even decided to follow ActiveRecord in including the ability to identify associations between the different models. The following is an example of how to define associations between two models:
//new version of JazzLegend model Artist = new JazzRecord.Model({ table: "artists", foreignKey: "artist_id", hasMany: {albums: "albums"}, columns: { name: "text", genre: "text", } }); //associated model Album = new JazzRecord.Model({ table: "albums", belongsTo: {artist: "artists"}, columns: { title: "text", year: "text", artist_id: "number" } });
Programming using Language Extensions
Several language extensions have been introduced in previous sections of the article. Let’s take a closer look at a specific scenario and show how each of them would implement their respective table. We will demonstrate how each of the language extensions are used to create a Customer table. The Customer table is very simple; it will contain two fields (an id and name).
- ActiveRecord
For ActiveRecord in Ruby on Rails, the syntax to create the table is contained within the Customer class that inherits from the ActiveRecord class. No external tools are required to generate the Ruby code, only the Ruby interpreter.
class Customer < ActiveRecord::Migration def self.up create_table :customer do |c| c.string :name c.string :id end end def self.down drop_table :customer end end
Now create a new Customer in Ruby, update the attributes, and save the object. The .save method will actually update the database table.
n = Customer.new n.id = “1” n.name = “Customer 1” n.save
- ADO.NET Entity Framework
ADO.NET requires that you use the Entity Model Designer which is part of Microsoft Visual Studio. The Designer allows you to create your model which includes any entities and associations.
The Designer will ultimately generate an XML file that represents the Entity Data Model.
<!-- A snippit from the xml file – shows the Customer definion --> <!-- There are not associations in out example --> <EntityType Name = "Customer"> <Property Name = "Name" Type = "String" /> <Property Name = "id" Type = "String" Nullable = "false" /> </EntityType>
In code for the Customer object, the setter on the class would look something like this.
set { this.CategoryReference.EntityKey = new EntityKey("CustomerEntities.Category", "id", “name”); }
- Django
In Django, a model is defined to represent a customer.
from django.db import models class Customer(models.Model): name= models.CharField(max_length=200)
After creating a model for a customer it will generate a corresponding table. Note that “id” is included as part of the model, so this might cause some unexpected issues if you planned to use id differently.
BEGIN; CREATE TABLE myapp_customer ( "id" serial NOT NULL PRIMARY KEY, "name" varchar(200), );
Create a new instance of a Customer and save it.
c = Customer(name=’Customer 1’) c.save() c.id # Returns the ID of your new object.
- Enterprise Objects Framework
The biggest downside with EOF and WebObjects is that it is not free. The Server and development environment is fairly expensive. However, here is a quick look at how you would create an EOF model that represents the classes, attributes and the objects.
Generate the Customer definition using the EOModler UI.
The code to create a new instance / database entry is fairly intuitive.
EOEditingContext ec = new EOEditingContext(); Customer c = new Customer(); c.id = "1"; c.name = "Customer 1"; ec.add(c); ec.saveChanges();
As you saw in some of the examples above, 2 of the 4 language extensions require external tools to generate the hooks in to the language.
Conclusion
Depending on what language you plan to use for your application will dictate what extensions and tools you will use. If you are driven by cost, then some of the choices are obvious to remove, otherwise you might be driven by you familiarity with a particular language or existing tool set. Either way one can see how all of the languages have attempted to simplify the process of accessing data in an external datastore. There is no clear victor in these comparisons, and we should believe the situation will dictate which language to use.
What’s Next?
In the next article for which the link does not exist yet, we will look at another style of metaprogramming, CRC Cards, one of the simplest methods of doing object oriented design. These cards are a way to capture the initial relationships between objects for a given system. CRC cards will help determine the evolution of these relationships before any code is written. You can learn very quickly about CRC cards by taking a close look at the software used to create CRC cards, and other artifacts of o-o design.
References
- Comparison of web application frameworks
- List of object-relational mapping software (Wikipedia.org)
- ActiveRecord Ruby (Wikipedia.org)
- ADO.NET Entity Framework (Wikipedia.org)
- Django (Wikipedia.org)
- Enterprise Objects Framework (Wikipedia.org)
- Programming Ruby - The Pragmatic Programmer's Guide
- Ruby – A Programmers Best Friend
- Django Project (Djangoproject.com)
- ADO.NET (Micorsoft.com)
- Enterprise Objects Framework (Apple.com)