开发者

What is the Algorithm for an ORM?

I've been digging around for an ORM to use in a php/mysql application. However none quite grab my attention past "hello world" tests. So, I decided to do some research and try to code my own custom ORM. However I haven't been able to find resources that explain at code level how开发者_JAVA百科 to handle db relationships. The concept of how an ORM works is clear but when trying to lay it out in code I don't know what the best approach is. Is it best to build several small queries or to build one complex query for every posible scenario? Any insight into the algorithm or architecture of an ORM is welcome!


Well let us make some ORM framework on the fly. As you marked php tag let us code it in PHP.

But before we write it we must know some basic concepts or some basic terminology about orm related subjects. In this example we will have:

  1. ORM framework - ORM framework takes responsibility to take care about server connections and server connection abstractions. (Full orm frameworks also support automatic class to table mappings).

  2. Data layer - This part is responsible for mapping classes to tables. For example data access layer knows how to save specific class object to actual table and how to load specific table to specific class object. (NOTE: Almost any recent ORM framework can avoid you from this layer. For example http://dbphp.net or Doctrine will support every aspect of this layer plus relations and even auto table generation).

  3. Business layer - This layer contains your actual working classes business layer often stands for model or model includes business layer

Let us begin our example from Business layer or model. Our very very simple project which saves and loads users will have one class business layer:

<?php
class user
{
    public $id;
    public $name
    public function __construct ($name=null)
    {
        $this->name = $name;
    }
}
?>

As you see your business layer or model knows nothing about where and how it is saved or loaded. It just does only handle project related business. That's the point the layer name comes from.

Second, let us make a simple ORM framework:

<?php

//The connection link which can be changed any time
class link
{
    public $link;
    public function __construct ($hostname, $database, $username, $password)
    {
        $this->link = new \PDO ('mysql:host='.$hostname.';dbname='.$database, $username, $password);
        $this->link->query('use '.$database);
    }
    public function fetch ($query)
    {
        $result = $this->link->query($query)->fetch();
    }
    public function query ($query)
    {
        return $this->link->query($query);
    }
    public function error ()
    {
        return $this->link->errorInfo();
    }
}

//A structure which collects all link(s) and table/class handlers togather
class database
{
    public $link;
    public $tables = array ();
    public function __construct ($link)
    {
        $this->link = $link;
        table::$database = $this;
    }
}

//A basic table handler class
//In recent ORM frameworks they do all the default mappings
class table
{
    public static $database;
}
?>

As you noticed our table class in our ORM framework seems very poor. But if this framework was a complex framework it would support also data layer and had all functionality to work with any table.

But because you need to know how ORM frameworks work in this case we will make data layer handlers for every class in our business layer.

So this is your data layer. It is so self descriptive that I think it does not need any documentation:

<?php
class users extends table
{
    public function create ($row)
    {
        $return = new user ();
        $return->id = $row[0];
        $return->name = $row[1];
        var_export($row);
        return $return;
    }
    public function load ($id=null)
    {
        if ($id==null)
        {
            $result = self::$database->link->fetch("select * from users");
            if ($result)
            {
                $return = array();
                foreach ($result as $row)
                {
                    $return[$row[0]] = $this->create($row);
                }
                return $return;
            }
        }
        else
        {
            $result = self::$database->link->fetch("select * from users where id='".$id."'");
            if ($result)
            {
                return $this->create(reset($result));
            }
            else
            {
                echo ("no result");
            }
        }
    }
    public function save ($user)
    {
        if (is_array($save))
        {
            foreach ($save as $item) $this->save ($item);
        }
        if ($user->id==null)
        {
            return self::$database->link->query("insert into users set
                                                 name='".$user->name."'");
        }
        else
        {
            return self::$database->link->query("update users set name='".$user->name."'
                                                 where id='".$user->id."'");
        }
    }
    public function delete ($user)
    {
        self::$database->link->query ("delete from users where id='".$user->id."'");
    }
}
?>
  1. At last let us init $database object
  2. Establish some to some sql server link.
  3. Add user class handler to database.
  4. Use it.

Here is it in work:

<?
$database = new database (new link('127.0.0.1', 'system_db', 'root', '1234'));
$database->tables['users'] = new users();

if (!$database->tables['users']->save (new user('Admin')))
{
    var_export($database->link->error());
}

var_export($database->tables['users']->load(2));
?>

If you need to dive in other concepts of php ORM's feel free to visit

  1. Doctrine - http://www.doctrine-project.org/ - Full functional complex php ORM framework
  2. db.php - http://dbphp.net/ - Full functional but very easy php ORM framework.


Many ORMs these days are built around the Active Record pattern or variations thereof. In this scheme, you usually have automatically generated classes that correspond to each table in the database, each of those classes return an instance of themselves or of a subclass that correspond to each row in the table:

For example, if you have a Users table:

$user_list = Users.getAllUsers(); //SELECT * FROM Users
//foreach row, create a new User() instance
$user_list[0].name = "Peter";
//UPDATE Users SET name = 'Peter' WHERE user_id = <$user_list[0].id>
$user_list[0].commit(); 

About implementation, it's best to try to minimize the amount of queries sent to the server, but it's not always trivial nor desirable.


ORMs are not simple. Your ORM will be neither simple or efficient. If it's either of these then your application is simple enough to not need one in the first place, or you're punting when the problem gets hard and simply not using it.

Simple CRUD mapping an object to a table is easy. Start adding in relationships or collections, and everything goes to pot. Then there's queries, etc. The complexity increases in a non-linear, accelerating fashion.

Then the inevitable need for caching just to get it to perform adds even more fun and excitement to the project.

Pretty soon your project is consumed in tweaking, maintaining, and debugging the internal ORM, instead of advancing your project. If you took the time you invested in your ORM and simply wrote a DAO layer with SQL, your project would be farther along, simpler, and more efficient.

Frankly, adopting an ORM is hard enough to justify, depending on the project scale. Writing your own is even more likely not worth the investment.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜