"…mais ce serait peut-être l'une des plus grandes opportunités manquées de notre époque si le logiciel libre ne libérait rien d'autre que du code…"

Mapping objet relationnel avec NHibernate, SqlAlchemy et RubyOnRails

Posted by patrick sur août 17, 2007

D’abord quelques définitions:

http://fr.wikipedia.org/wiki/Object-relational_mapping (« L’object-relational mapping (ORM), que l’on pourrait traduire par « correspondance entre monde objet et monde relationnel » est une technique de programmation informatique qui crée l’illusion d’une base de données orientée objet à partir d’une base de données relationnelle en définissant des correspondances entre cette base de données et les objets du langage utilisé« )

http://fr.wikipedia.org/wiki/Hibernate (« Hibernate est un framework open source gérant la persistance des objets en base de données relationnelle. Hibernate est adaptable en terme d’architecture, il peut donc être utilisé aussi bien dans un développement client lourd, que dans un environnement web léger de type Apache Tomcat ou dans un environnement J2EE complet : WebSphere, JBoss Application Server et WebLogic de BEA Systems (voir (en) BEA Weblogic).

…NHibernate est un framework open source gérant la persistance des objets en base de données relationnelle. Il est l’implémentation .NET de Hibernate qui a vu le jour en Java« )

Le patron de conception ActiveRecord

http://fr.wikipedia.org/wiki/Active_record_%28patron_de_conception%29 (« En génie logiciel, le patron de conception (design pattern) active record est une approche pour lire les données d’une base de données. Les attributs d’une table ou d’une vue sont encapsulés dans une classe. Ainsi l’objet, instance de la classe, est lié à un tuple de la base. Après l’instanciation d’un objet, un nouveau tuple est ajouté à la base au moment de l’enregistrement. Chaque objet récupère ses données depuis la base; quand un objet est mis à jour, le tuple auquel il est lié l’est aussi. La classe implémente des accesseurs pour chaque attribut« )

http://www.theserverside.com/tt/articles/article.tss?l=RailsHibernate (« ActiveRecord is « an object that wraps a row in a database table or view, encapsulates database access and adds domain logic on that data »[Fowler, 2003]. This means the ActiveRecord has « class » methods for finding instances, and each instance is responsible for saving, updating and deleting itself in the database. It’s pretty well suited for simpler domain models, those where the tables closely resemble the domain model. It is also generally simpler then the more powerful, but complex Data Mapper pattern« )

Le patron de conception DataMapper

http://martinfowler.com/eaaCatalog/dataMapper.html (« Objects and relational databases have different mechanisms for structuring data. Many parts of an object, such as collections and inheritance, aren’t present in relational databases. When you build an object model with a lot of business logic it’s valuable to use these mechanisms to better organize the data and the behavior that goes with it. Doing so leads to variant schemas; that is, the object schema and the relational schema don’t match up….The Data Mapper is a layer of software that separates the in-memory objects from the database. Its responsibility is to transfer data between the two and also to isolate them from each other. With Data Mapper the in-memory objects needn’t know even that there’s a database present; they need no SQL interface code, and certainly no knowledge of the database schema« )

http://www.theserverside.com/tt/articles/article.tss?l=RailsHibernate (« The Data Mapper is « a layer of mappers that moves data between objects and a database while keeping them independent of each other and the mapper itself »[Fowler, 2003]. It moves the responsibility of persistence out of the domain object, and generally uses an identity map to maintain the relationship between the domain objects and the database. In addition, it often (and Hibernate does) use a Unit of Work (Session) to keep track of objects which are changed and make sure they persist correctly.« )

http://en.wikipedia.org/wiki/SQLAlchemy (« SQLAlchemy is an open source SQL toolkit and object-relational mapper for the Python programming language released under the MIT License. SQLAlchemy provides « a full suite of well known enterprise-level persistence patterns, designed for efficient and high-performing database access, adapted into a simple and Pythonic domain language ». SQLAlchemy’s philosophy is that SQL databases behave less and less like object collections the more size and performance start to matter, while object collections behave less and less like tables and rows the more abstraction starts to matter. For this reason it has (like Hibernate for Java) adopted the Data Mapper pattern rather than the active record pattern used by a number of other object-relational mappers. »)

Le patron de conception UnitOfWork

http://martinfowler.com/eaaCatalog/unitOfWork.html (« When you’re pulling data in and out of a database, it’s important to keep track of what you’ve changed; otherwise, that data won’t be written back into the database. Similarly you have to insert new objects you create and remove any objects you delete…A Unit of Work keeps track of everything you do during a business transaction that can affect the database. When you’re done, it figures out everything that needs to be done to alter the database as a result of your work« )

http://www.sqlalchemy.org/features.html (« The Unit Of Work system, a central part of SQLAlchemy’s Object Relational Mapper (ORM), organizes pending create/insert/update/delete operations into queues and flushes them all in one batch. To accomplish this it performs a topological « dependency sort » of all modified items in the queue so as to honor foreign key constraints, and groups redundant statements together where they can sometimes be batched even further. This produces the maxiumum efficiency and transaction safety, and minimizes chances of deadlocks. Modeled after Fowler’s « Unit of Work » pattern as well as Hibernate, Java’s leading object-relational mapper.[More]« )

Comparaison de Hibernate avec le patron de conception ActiveRecord de Ruby On Rails

Différence d’architecture logicielle:

– http://www.theserverside.com/tt/articles/article.tss?l=RailsHibernate (« The core difference between Rails ActiveRecord and Hibernate is the architectural patterns the two are based off of. Rails, obviously, is using the ActiveRecord pattern, where as Hibernate uses the Data Mapper/Identity Map/Unit of Work patterns. Just knowing these two facts gives us some insight into potential differences…general implication of which should be fairly obvious. The ActiveRecord (Rails) will likely be easier to understand and work with, but past a certain point more advanced/complex usages will likely be difficult or just not possible. The question is of course, when or if many projects will cross this line. Let’s look at some specifics of the two frameworks. To illustrate these differences, we will be using code from my « Project Deadwood » sample app. (Guess what I’ve been watching lately.🙂

Exemples de code:

Soit une table créée avec l’ordre SQL suivant:

create table miners (

   id BIGINT NOT NULL AUTO_INCREMENT,

   first_name VARCHAR(255),

   last_name VARCHAR(255),

   primary key (id)

)

Avec RubyOnRails:

Your corresponding ruby class (miner.rb) and sample usage looks like this.

class Miner < ActiveRecord::Base

endminer.first_name = "Brom"

Avec Hibernate:

On the other hand, your Hibernate class (Miner.java) specifies the fields, getters/setters and xdoclet tags looks like so.

/**  * @hibernate.class table="miners"  */
public class Miner
{
private String firstName;
private String lastName;     /**      * @hibernate.id generator-class="native"      */
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }      /**      * @hibernate.property column="first_name"      */
public String getFirstName() { return firstName; }
public void setFirstName(String firstName) { this.firstName = firstName; }      /**      * @hibernate.property column="last_name"      */
public String getLastName() { return lastName; }
public void setLastName(String lastName) { this.lastName = lastName; }
}
miner.setFirstName("Brom");

Avec sqlalchemy:

# describe a table called 'miner',  query the database for its columns

miners_table = Table('miners', meta, autoload=True, autoload_with=engine)
>>> class Miner(object):

...     def __init__(self, first_name, last_name ):

...         self.first_name = first_name

...         self.last_name = last_name

...

...     def __repr__(self):

...        return "<Miner(%r,%r)>" % (self.first_name, self.last_name)
mapper(Miner, miners_table) 
theMiner = Miner(first_name = "Brom")

Associations

http://www.theserverside.com/tt/articles/article.tss?l=RailsHibernate (« In the last section, the Miner class we looked at was single table oriented, mapping to a single miners table. ORM solutions support ways to map associated tables to in memory objects, Hibernate and Rails are no different. Both handle the most of the basic mapping strategies. Here’s a non-exhaustive list of association supported by both of them, including the corresponding Hibernate – Rails naming conventions where appropriate.

  • Many to One/One to one – belongs_to/has_one
  • One to Many (set) – has_many
  • Many to Many (set) – has_and_belongs_to_many »)

Exemples d’associations

« As a comparative example, lets look at the many to one relationship. We are going to expand our Deadwood example from part I. We add to the Miner a many to one association with a GoldClaim object. This means there is a foreign key, gold_claim_id in the miners table, which links it to a row in the gold_claims table. »

Avec Hibernate:

(Java)

public class Miner {

   // Other fields/methods omitted    private GoldClaim goldClaim;

    /**

     * @hibernate.many-to-one column="gold_claim_id"

     *         cascade="save"

     */

    public GoldClaim getGoldClaim() { return goldClaim; }

    public void setGoldClaim(GoldClaim goldClaim) {

        this.goldClaim = goldClaim;

    }

}

Avec RubyOnRails:

(Rails)

class Miner < ActiveRecord::Base

    belongs_to :gold_claim

end

Avec Sqlalchemy :

parent_table = Table('parent', metadata,

    Column('id', Integer, primary_key=True),

    Column('child_id', Integer, ForeignKey('child.id')))



child_table = Table('child', metadata,

    Column('id', Integer, primary_key=True),

    )



class Parent(object):

    pass

 class Child(object):

    pass

 mapper(Parent, parent_table, properties={

    'child':relation(Child)

})



mapper(Child, child_table)

Pour aller plus loin

http://www.castleproject.org/activerecord/gettingstarted/index.html ( » The Castle ActiveRecord project is an implementation of the ActiveRecord pattern for .NET. The ActiveRecord pattern consists on instance properties representing a record in the database, instance methods acting on that specific record and static methods acting on all records… Complex databases structures (legacy databases mostly) usually are not covered by the range of mapping features supported by ActiveRecord. In this case you might consider using NHibernate directly« )

http://www.sqlalchemy.org/docs/choose.html (« La documentation de sqlalchemy »)

http://en.wikipedia.org/wiki/Nhibernate (« NHibernate is an Object-relational mapping (ORM) solution for the Microsoft .NET platform. It is licensed under the GNU Lesser General Public License.It is a port of the popular Java O/R mapper Hibernate to .NET. Version 1.0 mirrors the feature set of Hibernate 2.1, adding a number of features from Hibernate 3.

NHibernate 1.2.0, released May of 2007, introduces many more features from Hibernate 3 and support for .NET 2.0, stored procedures, generics and nullable types« )

http://www.hibernate.org/343.html (« NHibernate 1.2 introduces many additional features from Hibernate 3. Details about the new features can be found in this blog post. »)

http://blog.hibernate.org/cgi-bin/blosxom.cgi (« The groupblog of the Hibernate Team »)

http://blog.hibernate.org/cgi-bin/blosxom.cgi/Sergey%20Koshcheyev/nhibernate12-is-here.html (« NHibernate 1.2 is not a drop-in replacement for NHibernate 1.0. Before you jump to upgrading all your applications to NHibernate 1.2, note that there are several things that can break. The migration guide in the Wiki contains information about all the changes you need to make to successfully migrate...The next major release of NHibernate will drop support for .NET 1.1. We will continue porting the remaining Hibernate 3 features over to NHibernate. »)

http://www.ayende.com/Blog/category/510.aspx (« Les principales nouvelles sur NHibernate« )

http://www.ayende.com/Blog/ (Blog principal de Ayende @ Rahien)

http://www.hibernate.org/362.html (« NHibernate Quick Start Guide

2 Réponses to “Mapping objet relationnel avec NHibernate, SqlAlchemy et RubyOnRails”

  1. […] Plein d’info sur le blog de Patrick Vergain […]

  2. mdipierro said

    Avec gluon

    db.define_table(‘child’,SQLFIeld('name'))
    db.define_table(‘parent’, SQLField('name'),SQLField(‘child_id’, db.child))

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s

 
%d blogueurs aiment cette page :