ActiveRecord はかなり便利な O/R mapper ですが,さらに上(?)がありました.
- DataMapper
なお,このエントリは 0.9.11 をベースに書いています.
このエントリの目次と他エントリへのリンク
概要
ActiveRecord とは異なり,スキーマ定義は全てモデルに記述する (ActiveRecord だとマイグレーションとして記述).
とにかく,すべての定義がモデル定義に集中する.
class Post include DataMapper::Resource property :id, Integer, :serial => true property :title, String property :body, Text property :created_at, DateTime end
「なぜ DataMapper なのか?」については以下を参照してください (微妙な訳ですが...).
→ http://d.hatena.ne.jp/KrdLab/20090503/1241331628
接続
といっても,以下のコードが即 DB に接続するわけではない (Adapter を作成するだけ).
DataMapper.setup(:default, "mysql://localhost/dm_test")
詳細設定の場合は以下の通り.
DataMapper.setup(:default, { :adapter => "mysql", :database => "データベース名", :username => "ユーザ", :password => "パスワード", :host => "localhost" })
Logger
DataObjects::Mysql.logger = DataObjects::Logger.new('log/dm.log', 0)
ってやると,こんな感じでログがとれる.
Sun, 05 Jul 2009 08:36:07 GMT ~ debug ~ (0.028012) INSERT INTO `people` (`age`, `name`) VALUES (10, 'aaa')
Sun, 05 Jul 2009 08:36:07 GMT ~ debug ~ (0.000021) INSERT INTO `people` (`age`, `name`) VALUES (20, 'bbb')
Sun, 05 Jul 2009 08:36:07 GMT ~ debug ~ (0.000018) INSERT INTO `people` (`age`, `name`) VALUES (30, 'ccc')
Sun, 05 Jul 2009 08:36:07 GMT ~ debug ~ (0.000017) INSERT INTO `people` (`age`, `name`) VALUES (31, 'ddd')
Property 定義
Validation 指定
作成
Post.create(:title => '作り方 1', :body => 'create した.') post = Post.new post.title = '作り方 2' post.body = 'new してから save した.' post.save post = Post.first_or_create(:title => '作り方 1') p post
結果は以下の通り.
mysql> select * from posts; +----+-------------+---------------------------------+---------------------+ | id | title | body | created_at | +----+-------------+---------------------------------+---------------------+ | 1 | 作り方 1 | create した. | 2009-05-03 00:14:34 | | 2 | 作り方 2 | new してから save した. | 2009-05-03 00:14:34 | +----+-------------+---------------------------------+---------------------+
読み取り
主キーによる検索.
Post.get(100) # 見つからないときは nil Post.get!(100) # 見つからないときは ObjectNotFoundError # ↑#<DataMapper::ObjectNotFoundError: Could not find Post with key [100]> とかいわれる
すべて取得する.
Post.all Post.all.each {|r| puts "#{r.title}, #{r.body}" }
ActiveRecord っぽくもある.
Post.first(:created_at.lt => Time.now) Post.find(:first, :conditions => ['created_at < ?', Time.now])
演算子が使える.
http://datamapper.org/doku.php?id=docs:finders
- gt: よりも大きい
- lt: よりも小さい
- gte: 以上
- lte: 以下
- not: 等しくない
- like: マッチ (LIKE 指定)
- in: を含む (引数に配列を渡すと自動的にこれを指定したことになる)
例
Post.all(:title.like => 'title%', :id => [*1..5])
更新
attribute の変更方法.
post.title = '変更したよ' post.attributes = {:title => '変更したよ'} post.attribute_set(:title, '変更したよ') post.save
これも OK.
post.update_attributes(:title => '変更したよ')
オブジェクトが変更されていることを確認.
変更されていれば true が返ってくる.
post.dirty?
post.attribute_dirty?(:title)
削除
post = Post.first
post.destroy
消えちゃいます.
トランザクション
Model 内に記述する.
実験してみた → http://d.hatena.ne.jp/KrdLab/20090914/1252864716
アソシエーション
1:N とか 1:N:1 とか.
以下,基本的な使い方.
class Post include DataMapper::Resource property :id, Integer, :serial => true property :title, String property :body, Text property :created_at, DateTime has n, :comments end class Comment include DataMapper::Resource property :id, Serial property :posted_by, String property :email, String property :url, String property :body, Text belongs_to :post end
comments テーブルは以下の通り (post_id が追加される).
mysql> describe comments; +-----------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-----------+-------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | posted_by | varchar(50) | YES | | NULL | | | email | varchar(50) | YES | | NULL | | | url | varchar(50) | YES | | NULL | | | body | text | YES | | NULL | | | post_id | int(11) | YES | | NULL | | +-----------+-------------+------+-----+---------+----------------+
さっそく作成してみる.
post = Post.get(3) comment = post.comments.build(:posted_by => 'krdlab', :body => 'This is the comment.') comment.save
レコードが追加された.
mysql> select * from comments; +----+-----------+-------+------+----------------------+---------+ | id | posted_by | email | url | body | post_id | +----+-----------+-------+------+----------------------+---------+ | 1 | krdlab | NULL | NULL | This is a comment. | 3 | +----+-----------+-------+------+----------------------+---------+
別の方法.
comment = Comment.create(:posted_by => 'krdlab', :body => 'hogehoge.') post = Post.get(3) post.comments << comment post.save
またしても追加された.
mysql> select * from comments; +----+-----------+-------+------+----------------------+---------+ | id | posted_by | email | url | body | post_id | +----+-----------+-------+------+----------------------+---------+ | 1 | krdlab | NULL | NULL | This is a comment. | 3 | | 2 | krdlab | NULL | NULL | hogehoge. | 3 | +----+-----------+-------+------+----------------------+---------+
ところで
ActiveRecord と DataMapper ですが,これらはシステム設計におけるパーシステンス層の設計パターン名そのままですね.