アクティブレコードパターン

ソフトウェアエンジニアリングにおいてアクティブレコードパターンはアーキテクチャパターンの一種です。これは、リレーショナルデータベースのメモリ内オブジェクトデータを格納するソフトウェアに見られます。このパターンは、マーティン・ファウラーが2003年に著した『Patterns of Enterprise Application Architecture』の中で名付けられました[1] [2]このパターンに準拠するオブジェクトのインターフェースには、挿入、更新、削除などの機能に加え、基盤となるデータベーステーブルの列にほぼ直接対応するプロパティが含まれます。

アクティブレコードパターンは、データベース内のデータにアクセスするためのアプローチですデータベースのテーブルまたはビューはクラスにラップされます。したがって、オブジェクトインスタンスはテーブル内の単一の行に関連付けられます。オブジェクトの作成後、保存時に新しい行がテーブルに追加されます。ロードされたオブジェクトは、データベースから情報を取得します。オブジェクトが更新されると、テーブル内の対応する行も更新されます。ラッパークラスは、テーブルまたはビューの各列に対してアクセサ メソッドまたはプロパティを実装します。

このパターンは、オブジェクト永続化ツールやオブジェクト・リレーショナル・マッピング(ORM)でよく使用されます。通常、外部キー関係は、プロパティを介して適切な型のオブジェクトインスタンスとして公開されます。

実装

この概念の実装は、多くのプログラミング環境の様々なフレームワークで見つけることができます。例えば、partsデータベースに列name(文字列型)と列price(数値型)を持つテーブルがあり、クラスにアクティブレコードパターンが実装されている場合Part、擬似コードは 次のようになります。

パーツpart = new Part ( "サンプルパーツ" 123.45 );     

parts指定された値を持つテーブルに新しい行を作成します。これは、 SQLコマンド とほぼ同等です。

INSERT INTO parts ( name , price ) VALUES ( 'Sample part' , 123 . 45 );       

逆に、このクラスを使用してデータベースをクエリすることもできます。

パーツb = parts.stream ( ) . filter ( p -> "gearbox" .equals ( p.getName ( ) )) . findFirst ( ) . orElse ( null ) ;        

これは、テーブルPart内の列の値が「gearbox」である最初の一致行に基づいて新しいオブジェクトを検索します。使用されるSQLコマンドは、データベースのSQL実装の詳細に応じて、次のようなものになります。partsname

SELECT * FROM parts WHERE name = 'gearbox' LIMIT 1 ; -- MySQL または PostgreSQL          

さまざまなライブラリがアクティブレコードパターンフレームワークを実装しています。例えば、ライブラリのPOCO C++ライブラリPoco::ActiveRecordなどです。[3]

これは、 JavaUserにおけるアクティブレコードオブジェクトの簡単な例ですクラスはモデルとデータアクセスオブジェクトの両方として機能し、、、メソッドを提供しますUsersave()find()delete()

パッケージorg.wikipedia.examples ; java.sql.Connectionをインポートします。java.sql.DriverManagerインポートします。java.sql.PreparedStatementインポートします。java.sql.ResultSetインポートします。java.sql.SQLExceptionインポートします。java.sql.Statementインポートします      パブリッククラスUser { private int id ; private String name ; private String email ;             public User ( String name , String email ) { this.name = name ; this.email = email ; }             パブリックint getId () {戻り値 id ; }       パブリックvoid setId ( int id ) { this . id = id ; }         パブリック文字列 getName () {戻り値 name ; }       public void setName ( String name ) { this . name = name ; }         public String getEmail () {メールを返す; }       public void setEmail ( String email ) { this . email = email ; }         public void save ( ) { try ( Connection conn = DriverManager.getConnection ( " jdbc : mysql ://localhost:3306/mydb" " user " " password " ) ) { if ( this.id == 0 ) { String sql = " INSERT INTO users ( name , email) VALUES(?, ?) " ; try ( PreparedStatement stmt = conn.prepareStatement ( sql Statement.RETURN_GENERATED_KEYS ) ) { stmt.setString ( 1 this.name ) ; stmt.setString ( 2 this.email ) ; stmt.executeUpdate ( ) ; ResultSet rs = stmt.getGeneratedKeys ( ) ; if ( rs.next ( ) ) { this.id = rs.getInt ( 1 ) ; } } } else { String sql = "UPDATE users SET name = ?、email = ? WHERE id = ? " ; try ( PreparedStatement stmt = conn.prepareStatement ( sql ) ) { stmt.setString ( 1 this.name ) ; stmt.setString ( 2 this.email ) ; stmt.setInt ( 3 this.id ) ; stmt.executeUpdate ( ) ; } } } catch ( SQLException e ) { System.err.printf ( " SQLException発生まし: % s % n " e .                                                                         getMessage ()); e.printStackTrace ( ) ; } }    public static User find ( int id ) { try ( Connection conn = DriverManager.getConnection ( " jdbc : mysql://localhost:3306/mydb" " user" " password" )) { String sql = " SELECT * FROM users WHERE id = ?" ; try ( PreparedStatement stmt = conn.prepareStatement ( sql ) ) { stmt.setInt ( 1 id ) ; ResultSet rs = stmt.executeQuery (); if ( rs.next ( ) ) { User user = new User ( rs.getString ( " name " rs.getString ( " email " ) ) ; user.setId ( rs.getInt ( " id " ) ) ; return user ; } } } catch ( SQLException e ) { System.err . printf ( "SQLException が発生しました: %s%n" , e . getMessage ()); e . printStackTrace (); } return null ; }                                                        public void delete ( ) { try ( Connection conn = DriverManager.getConnection ( "jdbc:mysql://localhost:3306/mydb" " user " " password" )) { String sql = "DELETE FROM users WHERE id = ?" ; try ( PreparedStatement stmt = conn.prepareStatement ( sql ) ) { stmt.setInt ( 1 this.id ) ; stmt.executeUpdate ( ); } } catch ( SQLException e ) { System.err.printf ( " SQLExceptionが発生しました: % s % n " e.getMessage ( ) ) ; e.printStackTrace ( ) ; } } }                                   

批判

大きなファイル

データとデータベース アクセス メソッドは同じファイル内にあるため、これらのファイルは大きくなります。

単一責任原則と関心の分離

アクティブレコードパターンに対するもう一つの批判は、データベースとのやり取りとアプリケーションロジックの強い結合により、アクティブレコードオブジェクトが単一責任原則関心の分離に従っていないという点です。これは、これらの原則に適切に対応している多層アーキテクチャとは対照的です。[要出典] [要説明]このため、アクティブレコードパターンは、 CRUD機能を備えたフォームオーバーデータ型のシンプルなアプリケーション、またはアーキテクチャの一部としてのみ使用される場合に最も適しており、最も頻繁に使用されます。 [要出典]通常、その部分はデータアクセスであり、多くのORMがアクティブレコードパターンを実装する理由です。

参照

参考文献

  1. ^ EAAカタログのP - アクティブレコード
  2. ^ Fowler, Martin (2003). エンタープライズ・アプリケーション・アーキテクチャのパターン. Addison-Wesley. ISBN 978-0-321-12742-6
  3. ^ "Namespace Poco::ActiveRecord". docs.pocoproject.org . POCOプロジェクト. 2025年10月18日閲覧
「https://en.wikipedia.org/w/index.php?title=Active_record_pattern&oldid=1322036298#Ruby」から取得