ラベル jPersist の投稿を表示しています。 すべての投稿を表示
ラベル jPersist の投稿を表示しています。 すべての投稿を表示

2008年1月31日木曜日

書評、色々リリース、他

クーリエジャポン

定期購読で毎月届くので、読んだ。今回はめづらしく、自分におもしろく感じる記事が少なかった。そんな中ひとつだけ「おもしろかったー!」と思ったのは「SPECIAL REPORT アメリカ"影の権力装置"ロビイストの世界に潜入する」という記事。アメリカでロビー活動をしている大きい会社に記者が”囮”操作を行う記事。これはおもしろかったし、何かこれからニュースを見るのにますます「ひねくれた」見方をしてしまうようになりそうだw ちなみに、定期購読は2006年の秋くらいに一年購読で申し込んだものがまだ届いている。その頃は隔週だったのが今は月刊になっているからなのだが、実は定期購読って期間が終わるタイミングにどぅなるのかがわからない。出版社の方から「次が最後のお届けとなります」とか連絡をくれるのだろぅか?連絡してくれないと、ウチの夫婦は気づかないぞw

FEST-assert

Swingの自動TestツールFESTのassertion用モジュール群です。ついさっき0.9がリリースされました。本体のFEST-swingはまだ0.8なのに。

jPersist

昨日に3.1.0がリリースされたよぅです。モチロン、[Single|Concrete]TableInheritanceの実装が含まれています。

Greasemonkeyのスクリプトを自作するしかない?

最近Lifhackの一環として以下の点についてと強く要求がある。
  • GMAILの画面にGoogleCalenderの直近4週間の予定を表示したい。
  • GoogleReaderの「後で必ず読む」というマークをRTMのタスクに登録したい(今はReader内に"!!1.必ず読め"とかタグを作ってる)。
これを実現するGreasemonkeyのScriptがみつからないので、自分で作ろうとしている。が!素でJavaScriptなんて組みたくないからjQueryを使いたいというところでいきなりつまづいている。うーーん。「Greasemonkeyで外部ライブラリを使用する」に関してはいくつか情報があるので、参考にさせていただいて目標達成しようと思います。

バナナ

今月の消費は18本/31日でした。バナナの消費を数えるサービスってないかなぁ。

Blogged with Flock

2008年1月27日日曜日

jPersistその後、他

jPersistその後

作者さまが実装、俺がTest、みたいなカンジで色々やりとりしていた結果、SingleTableInheritanceに加えてConcreteTableInheritanceも動作するようになりましたw作者様に感謝です。たぶん次のリリースではこれらが実装されたモノとなると思われます。 ここで思ったんだけど、今回の作業の進め方を振り返って見ると!
  • 私が「こう動作するべき」といった内容を仕様として伝える。
  • その手段はTestCaseで伝えた。英語の文章だと間違って伝わる可能性大だしw
  • そのTestCaseは、どちらかというと「あるべき振る舞いの表現」に近い。
  • そして作者さまが実装、確認。
  • 私が確認。
「言語の壁を越えて仕様を伝える」という意味では、中国に出すのも同じ。振る舞い駆動、いいのかもね。いや、いい方法であることはわかっていて、そぅあるべきだともわかっているんだけど、今回の件でより実感が沸いたなぁ。

デブサミ

申し込んだ。後は社内での外出許可をとるだけ。許可が降りなかったら有休を使うことにしよう。 嫁さんと手分けしてバラバラに申し込んだからかなり色々勉強になると思われる! 本当は社内の若い衆に行ってもらいたいところだが、あまりにも知識がなさすぎで、吸収できる内容も極端に小さいんだなぁ。もっと教育しろ!ってツッコミは無しでおながいします。俺の下なら教育すんだけどさ、俺の下じゃないんだよ!その他中堅連中はみんな勉強不足で部下どころか本人たちがまず話になってないしさー。
  • SECON0802019 デブサミ2008 2/13 14:20-15:05【13-D-4】VB資産のCurlマイ
    グレーション
  • SECON0802021 デブサミ2008 2/13 15:25-16:15【13-A-5】反復開発とテスト - 7年
  • SECON0802027 デブサミ2008 2/13 16:35-17:20【13-B-6】インターネット・アプリケーションを素早く作る―Project Zero
  • SECON0802031 デブサミ2008 2/13 17:40-19:00【13-A-7】パネルディスカッション:TPSで進化するアジャイル開発
  • SECON0802049 デブサミ2008 2/14 13:10-14:00【14-D-3】Seasarコミッタが教える実行速度が速いコードの書き方
  • SECON0802051 デブサミ2008 2/14 14:20-15:05【14-A-4】SaaSプラットフォーム上でのアプリケーション開発
  • SECON0802059 デブサミ2008 2/14 15:25-16:15【14-D-5】デベロッパーテスティング・ライブ - 自信を持ってコードを書くための心・技・体 -
  • SECON0802061 デブサミ2008 2/14 16:35-17:20【14-A-6】業務分析から設計・製造まで大幅な生産性向上を実現する開発方法~設計情報の一元管理による上流から下流への連携とテストケースの自動出力~
  • SECON0802066 デブサミ2008 2/14 17:40-19:00【14-A-7】ネット・コミュニケーション2.0

鍋パーティー

昨晩は社内の仲間で鍋パーティをやった。今回も盛況だったけど、おつまみが多すぎた。次回はメイン具材とおつまみのバランスをバッチリ適量で迎え撃つ!

2008年1月26日土曜日

jPersistの作者様にビクーリ!

昨晩、jPersistによるTableの継承の解決がおかしいという問題について「時期リリースで対応する」という作者様の回答を受けて「終了」ステータスにしたのだが、今朝早くにその「時期リリース候補」のモジュールが届いていたw 数時間で実装を試みた模様。すごい行動力にビクーリ!中を見ると「SingleTableInheritance」に加えて「ConcreteTableInheritance」も追加する修正が行われた模様。 まだ完全にはどうさしていないので、私の方でSingleTableInheritance用、ConcreteTableInheritance用、それぞれのTestを実装して、Greenにならない機能の報告を行ったり…といったやりとりしている状態だす。行動力がすごいなぁー。

Blogged with Flock

2008年1月25日金曜日

jPersistの件、解決(解決ではないが終了)

先のエントリに書いた、STIじゃないんじゃない?の件、作者様から以下の回答を頂戴しました。
ああ、指摘のとおりだね。次のリリースでそれぞれのパターンを区別して実装できるよう修正するよ。 だがしかし!jPersisの思想として「XMLやAnnotationを極力使わない」という方針もあるから、難しいね。各パターンを選択できるようにするにはAnnotationをいくつか増やさなければならない。
との事です。自分的にはTableの継承ってのは「O→R」に設計した時の一部のモノで、「R→O」で設計しちゃぅとあんまり気にしないと思っているので「Annotationが増えるといってもそれを使用しなければならない箇所は部分的なモノで、殆どの箇所ではそれを必要としないと思います。だから、そぅいったAnnotationは用意されていてもたぶんイーンダヨ!」とお礼も含めて返信しておきました。明日からはjPersistについては普通の関連の解決を試すことにしよう。 摩訶不思議な英文をがんばって解読してサポートしてくれる作者様、ほんっっとありがとうございます!

Blogged with Flock

jPersist問い合わせの結果

STIについて作者さまに問い合わせた結果、次のような回答をちょうだいした。
ドキュメントの不備で「基底クラスがテーブル名である必要があるように見えちゃうよね。 あなたの「Footballer」「Clicketer」のパターンであれば、それぞれに対応するテーブルを作成する必要があります。
…エエエエェェェー!?これって、つまり「SingleTable」で継承を解決してないのでは!?俺が間違ってるんだろうか?もぅワカラン。orz
  • Player...ID,nameを持つ。
  • Footballer extends Player...clubを持つ。
  • Clicketer extends Player...battingAverageを持つ。
この関係にある時、解決法方途しては次のようなパターンがある。
Single Table Inheritance
「Player」「Footballer」「Clicketer」全てのClassのメンバを保持するPlayersテーブルでやりくりする。
  • Players...id,name,club,battingAverage
Concrete Table Inheritance
サブクラスごとにTableを作成する。各Tableには基底クラスのメンバを持たせる。
  • Footballers...id,name,club
  • Clicketer...id,name,battingAverage
Class Table Inheritance
各Classに対応したTableを作成する。
  • Players...id,name
  • Footballers...club
  • Clicketers...battingAverage
この中で、SingleTableInheritanceはPlayerを扱うときにTableのJoinが発生しない。自分ではこれをやるには次のようなカンジの操作でできるはずだという理解をしている。
Footballer p0 = new Footballer("player01", "club01");
p0.save(dbm);
Clicketer c0 = new Clicketer("player01", 30L);
c0.save(dbm);
これで、勝手にPlayersTableに保存される「べき」。取得する時は、
Collection<Player> players = dbm.loadObjects(new ArrayList<Player>(), Player.class);
という具合に取得すれば、RDB的にはPlayersTableから取得し、Java的にはそれの各メンバのnullをチェックして「Footballer」「Clicketer」が生成される「べき」。Footballerなのにclubがnullだったりしたら解決できなさそぅだけど、それはO→Rする前にチェックするとして今は考えない。 …なんば間違っとぅとー!?わかんねぇ。 まぁ、継承の話よりも関連の話をもっと色々試す方が重要なんだけどね。気になってしまって。。小さか男ばい。

Blogged with Flock

2008年1月24日木曜日

jPersistその後、他

jPersistその後

SingleTableInheritanceの件は一旦調査を諦めて、作者の方に連絡する事にした。P of EAA: Single Table Inheritanceのモデルをそのまま使用した構成にしたけど、どうしてもサブクラスのTable名を解決できない。例えば、Footballerのインスタンスを作成してsave()すると、親クラスに対応するPlayersテーブルに保存してほしいのだが「Footballerテーブルが無ぇ」と言われてしまう。 下のようにjpersist.interfaces.TableMappingをDatabaseManagerに登録して無理やり名前解決をすればうまくいくが、これは何か違うし。
dbm.setGlobalMappers(new TableMapping() {
  public String getDatabaseTableName(String name) {
    if (name == null)
      return null;
    if (name != null
        && (name.equalsIgnoreCase("footballer") || name
            .equalsIgnoreCase("clicketer"))) {
      return "Players";
    } else {
      return StringUtils.camelCaseToUpperCaseUnderline(name);
    }
  }
}, null);
俺のSTIの理解が間違っているだけの可能性が大きいけど、jPersistのSTI関連のDocumentの在処でもいいから教えてくだされと連絡した。

バナナ

20日に3本パックを購入したが既に全滅(一本は嫁さんが喰った)。月曜日にも追加で2本パックを購入しておいたが、それも昨日喰ってしまった。シズラー行ったときに喰っておけば良かった!

2008年1月21日月曜日

jPersistでSingleTableInheritance(STI)の件、俺が間違ってました。

ConcreteTableInheritanceを実装しながら、「SingleTableInheritance(STI)」が動作しねぇぇ!と叫んでる恥ずかしい人を見かけたぜ。そんな恥ずかしいやつがどこにいたかって?俺だよ。 前回のエントリでjPersisがSTIを実装してるなんてウソじゃねぇのか、くらいの勢いでjPersistのせいにしようとしていたが、そもそも俺がやっていたのはSTIではなくConcreateTableInheritanceであった。jPersistの動きを追っかけていて、テーブル名の取得等をしている処理を見て「こ、この動きは…」となった。PofEAAの中身を再度確認しなおしました、はい。全部俺の問題。疑がわれるべきでなさそぅな人を疑いだした時は、大概俺が悪いのだ。 そんなワケで昨晩に再度チャレンジしたが…まだ動かないから報告できませんw

2008年1月17日木曜日

jPersist続き(問題発生)

  • あるTableの名称含んだTable名称があるとマズイ模様。例えば、先日の例でいうと「Member」というTableを使った。で、SingleTableInheritanceを試そうとして「SpecialMember」という特殊なMemberで試そうとしたらダメ。もぅめちゃはまった。Table名のマッピングでMemberの解決で「Member」「SpecialMember」の両方を拾ってしまう。基本的に「Table名=jcommontk.utils.StringUtils#camelCaseToUpperCaseUnderline(Model名+"s")」の法則で考えるから、Memberの解決を行っている箇所を修正してしまえばいいんだけど、そもそも俺の使い方がマズイのか?そーなんか?
  • 関連するテーブルで、直接save()とかDB操作しないClassはPOJOでも良さげ。ただ、そんな事は滅多に無いからやっぱ「jpersist.PersistentObject」を継承することになる。
  • ただし、直接操作が無いTableは「jpersist.PersistentObject」のSubClassである「jpersist.Entity」を継承するようにしといた方がいいのかも?
先日の例のModelを少し変えてSingleTableInheritanceを試みた。
hsqldb/sample.script
CREATE SCHEMA PUBLIC AUTHORIZATION DBA
CREATE MEMORY TABLE DEPARTMENTS(ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL PRIMARY KEY,NAME VARCHAR(100))
CREATE MEMORY TABLE MEMBERS(ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL PRIMARY KEY,DEPARTMENT_ID INTEGER NOT NULL,NAME VARCHAR(100),CONSTRAINT MEMERS_FKEY_01 FOREIGN KEY(DEPARTMENT_ID) REFERENCES DEPARTMENTS(ID) ON DELETE CASCADE ON UPDATE CASCADE)
CREATE MEMORY TABLE SUBTABLES(ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL PRIMARY KEY,DEPARTMENT_ID INTEGER NOT NULL,NAME VARCHAR(100),SPECIAL_PROPERTY VARCHAR(100),CONSTRAINT SUBTABLES_FKEY_01 FOREIGN KEY(DEPARTMENT_ID) REFERENCES DEPARTMENTS(ID) ON DELETE CASCADE ON UPDATE CASCADE)
CREATE USER SA PASSWORD ""
GRANT DBA TO SA
SET WRITE_DELAY 10
Model「Department」。PrimaryKeyの名称を「ID」にした。
package shin1o;

import java.util.Vector;

import jpersist.PersistentObject;

@SuppressWarnings("serial")
public class Department extends PersistentObject {
  Long id;
  String name;
  Vector<Member> members = new Vector<Member>();

  public Department() {}
  public Department(String _name) { name = _name; }

  public String toString() {
    return new StringBuilder().append("{id:").append(id).append(
        ", name:").append(name).append(", members:").append(
        members.toString()).append("}}").toString();
  }

  // Associations
  public Vector<Member> getDbAssociation(Member c) {
    return members;
  }
  public void setDbAssociation(Member c, Vector<Member> _members) {
    members = _members;
  }

  public Vector<Member> getMembers() { return members; }
  public void setMembers(Vector<Member> members) { this.members = members; }
  public Long getId() { return id; }
  public void setId(Long departmentId) { this.id = departmentId; }
  public String getName() { return name; }
  public void setName(String name) { this.name = name; }
}
Model「Member」。PrimaryKeyの名称を「ID」にして、SuperClassをjpersist.Entityに変更した。
package shin1o;

import jpersist.Entity;

@SuppressWarnings("serial")
public class Member extends Entity {
  Long id;
  String name;
  Long departmentId;

  public Member() { }
  public Member(String _name) { name = _name; }

  public String toString() {
    return new StringBuilder().append("{id:").append(id).append(
        ", departmentId:").append(departmentId).append(", name:")
        .append(name).append("}").toString();
  }

  public Long getId() { return id; }
  public void setId(Long memberId) { this.id = memberId; }
  public String getName() { return name; }
  public void setName(String _name) { this.name = _name; }
  public Long getDepartmentId() { return departmentId; }
  public void setDepartmentId(Long departmentId) { this.departmentId = departmentId; }
}
今回追加したModel「SubTable」。最初は「SpecialMember」だったが、エントリ頭の問題で適当な名前にした。Memberを継承している。 @SingleTableInheritanceアノテーションをClassに適用している。PDFのマニュアルを見ると「jpersist.interfaces.SingleTableInheritance」を実装またはSingleTableInheritanceアノテーション云々、と書いてある。今回はXMLもアノテーションも極力使用せずにActiveRecordを、と思ったのでinterfaceの方でやろうとしたらそんなinterfaceは存在しない。ドキュメントの更新がソースに追随していないよぅだ。
package shin1o;

import jpersist.annotations.SingleTableInheritance;

@SuppressWarnings("serial")
@SingleTableInheritance
public class SubTable extends Member {
  String specialProperty;

  public SubTable() { }
  public SubTable(String _name, String _specialProperty) {
    name = _name;
    specialProperty = _specialProperty;
  }

  public String toString() {
    String s = super.toString();
    s = s.substring(0, s.length() - 1);
    return new StringBuilder(s).append(", specialProperty:").append(
        specialProperty).append("}").toString();
  }

  public String getSpecialProperty() { return specialProperty; }
  public void setSpecialProperty(String specialProperty) { this.specialProperty = specialProperty; }
}
TestCase。先日のTestCase以下のメソッドを追加。実際には、フィールド名称を簡単にしたりしているからそのあたりも先日のモノに対して修正が必要。 やけにSystem.out.println()していたり、直接JDBCを操作したりしているのは調査のため。
  @Test
  public void 継承を使う() throws Exception {
    System.out.println("継承を使う() start.");
    Department department = dbm.loadObject(Department.class,
        "where :name like '%2'");
    System.out.println("継承を使う() load end. and add start.");
    department.getMembers().add(new SubTable("member_2_3", "subMember"));
    System.out.println("継承を使う() add SubTable end.");
    department.getMembers().add(new Member("member_2_4"));
    System.out.println("継承を使う() add Member end. and save start.");
    System.out.println(department);
    department.save(dbm);
    System.out.println("継承を使う() save end. and reload start.");
    System.out.println(department);

    try {
      jdbcQuery("select * from subtables");
      department = dbm.loadObject(Department.class,
          "where :name like '%2'");
      Collection<Member> members = loadObjects(Member.class);
      Collection<SubTable> subTables = loadObjects(SubTable.class);
      System.out.println("継承を使う() reload end.");
      System.out.println(department);
      assertEquals(6, members.size());
      assertEquals(1, subTables.size());
      assertEquals(4, department.getMembers().size());
    } finally {
      System.out.println("継承を使う() end.");
    }
  }

  void jdbcQuery(String sql) throws JPersistException, SQLException {
    ResultSet resultSet = dbm.getDatabase().executeQuery(sql)
        .getResultSet();
    int columnSize = resultSet.getMetaData().getColumnCount();
    System.out.println("jdbcQuery - " + sql);
    while (resultSet.next()) {
      ArrayList<Object> values = new ArrayList<Object>(columnSize);
      for (int i = 1; i <= columnSize; i++) {
        values.add(resultSet.getObject(i));
      }
      System.out.println(StringUtils.toString(values.toArray()));
    }
  }
これで実行してみると、DBへの保存はDEPARTMENT,MEMBER,SUBTABLEすべてにおいて成功する(JDBC操作はDBへの保存を確認するため)。が、最後の方のDEPARTMENTの取得で「MEMBER」しか自動取得してくれない。jPersist内で発行されたSQLを表示させてみると、DEPARTMENTS,MEMBERSのselect文が発行されているのにSUBTABLESへはselectが発行されていない。という問題がまだ未解決。jPersistの中をちょっと追っかけてみる必要がありそぅだ。 ちなみに、SQLの表示はjpersist.DatabaseManager.setLogLevel()でLevel.FINEを指定すればおk。誰か、タスケテ!MLも見当たらないし、連絡の取り方がわからんのだ。

2008年1月15日火曜日

jPersistを試してみる

JavaでActiveRecord、てのが気になったので試してみることにした。サポートされているDBはPDFのリファレンスを見ると次の通りだそぅだ。
Supported Databases Right now our focus is on adding support for as many databases as we can, and jPersist currently has complete, and fully tested, support for:
  • MySqlDB2
  • Oracle
  • Derby
  • HSQL
  • PostgreSQL
  • H2
HSQLDBを使う前提での作業。
  • hsqldb/sample.properties
    #HSQL Database Engine 1.8.0.7
    #Wed Jan 16 03:33:41 GMT+09:00 2008
    hsqldb.script_format=0
    runtime.gc_interval=0
    sql.enforce_strict_size=false
    hsqldb.cache_size_scale=8
    readonly=false
    hsqldb.nio_data_file=true
    hsqldb.cache_scale=14
    version=1.8.0
    hsqldb.default_table_type=memory
    hsqldb.cache_file_scale=1
    hsqldb.log_size=200
    modified=no
    hsqldb.cache_version=1.7.0
    hsqldb.original_version=1.8.0
    hsqldb.compatible_version=1.8.0
    
  • hsqldb/sample.script
    CREATE SCHEMA PUBLIC AUTHORIZATION DBA
    CREATE MEMORY TABLE DEPARTMENTS(DEPARTMENT_ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL PRIMARY KEY,NAME VARCHAR(100))
    CREATE MEMORY TABLE MEMBERS(MEMBER_ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 0) NOT NULL PRIMARY KEY,DEPARTMENT_ID INTEGER NOT NULL,NAME VARCHAR(100),CONSTRAINT MEMERS_FKEY_01 FOREIGN KEY(DEPARTMENT_ID) REFERENCES DEPARTMENTS(DEPARTMENT_ID) ON DELETE CASCADE ON UPDATE CASCADE)
    CREATE USER SA PASSWORD ""
    GRANT DBA TO SA
    SET WRITE_DELAY 10
    SET SCHEMA PUBLIC
    
    非常に横に長いが、整形するとHSQLDBが解析に失敗するのでこのままの状態で。
  • src/main/resources/databases.xml
    <databases>
      <database name="studyJPersist_hsqldb" poolSize="10"
        driver="org.hsqldb.jdbcDriver" url="jdbc:hsqldb:file:hsqldb/sample" />
    </databases>
    class出力フォルダの直下にあれば良い。eclipseならsrc/databases.xmlになるかな。
  • 次にModelをふたつ作成。DEPARTMENTに複数のMEMBERがぶら下がるという関係。まずはDEPARTMENT
    package shin1o;
    
    import java.util.Vector;
    import jpersist.PersistentObject;
    
    @SuppressWarnings("serial")
    public class Department extends PersistentObject {
      Long departmentId;
    
      String name;
    
      Vector<Member> members = new Vector<Member>();
    
      public Department() {}
    
      public Department(String _name) { name = _name; }
    
      public String toString() {
        return new StringBuilder().append("{id:").append(departmentId).append(
            ", name:").append(name).append(", members:").append(
            members.toString()).append("}}").toString();
      }
    
      // Associations
    
      public Vector<Member> getDbAssociation(Member c) {
        return members;
      }
    
      public void setDbAssociation(Member c, Vector<Member> _members) {
        members = _members;
      }
    
      public Vector<Member> getMembers() { return members; }
    
      public void setMembers(Vector<Member> members) { this.members = members; }
    
      public Long getDepartmentId() { return departmentId; }
    
      public void setDepartmentId(Long departmentId) { this.departmentId = departmentId; }
    
      public String getName() { return name; }
    
      public void setName(String name) { this.name = name; }
    }
    
  • 次にぶら下がる方のMember。
    package shin1o;
    
    import jpersist.PersistentObject;
    
    @SuppressWarnings("serial")
    public class Member extends PersistentObject {
      Long memberId;
    
      String name;
    
      Long departmentId;
    
      public Member() { }
    
      public Member(String _name) { name = _name; }
    
      public String toString() {
        return new StringBuilder().append("{id:").append(memberId).append(
            ", departmentId:").append(departmentId).append(", name:")
            .append(name).append("}").toString();
      }
    
      public Long getMemberId() { return memberId; }
    
      public void setMemberId(Long memberId) { this.memberId = memberId; }
    
      public String getName() { return name; }
    
      public void setName(String _name) { this.name = _name; }
    
      public Long getDepartmentId() { return departmentId; }
    
      public void setDepartmentId(Long departmentId) { this.departmentId = departmentId; }
    }
    
  • TestClassを作成して、動作確認をしてみる。
    package shin1o;
    
    import static org.junit.Assert.assertEquals;
    
    import java.util.*;
    import jpersist.*;
    import org.junit.*;
    
    public class JPersistTest {
      static DatabaseManager dbm;
    
      @BeforeClass
      public static void setUp() throws JPersistException {
        DatabaseManager.setLogLevel(java.util.logging.Level.INFO);
        dbm = DatabaseManager
            .getXmlDefinedDatabaseManager("studyJPersist_hsqldb");
      }
    
      @AfterClass
      public static void tearDown() throws JPersistException {
        if (dbm != null && !dbm.isClosed()) {
          dbm.close();
        }
      }
    
      /**
       * {@link #before()} で作成したDepartmentのidを毎回保存しておく。
       */
      Long d0Id, d1Id, d2Id;
    
      /**
       * Testするたびに初期データを作り直す。
       * @throws Exception
       */
      @Before
      public void before() throws Exception {
        Department d0 = new Department("department0");
        d0.save(dbm);
        d0Id = d0.getDepartmentId(); // save後にIDを保存。
    
        Department d1 = new Department("department1");
        d1.getMembers().add(new Member("member_1_1"));
        d1.getMembers().add(new Member("member_1_2"));
        d1.getMembers().add(new Member("member_1_3"));
        d1.save(dbm);
        d1Id = d1.getDepartmentId();
    
        Department d2 = new Department("department2");
        d2.getMembers().add(new Member("member_2_1"));
        d2.getMembers().add(new Member("member_2_2"));
        d2.save(dbm);
        d2Id = d2.getDepartmentId();
      }
    
      @After
      public void after() throws Exception {
        // 全部消す
        Result<Department> departments = dbm.getDatabase().queryObject(
            Department.class);
        while (departments.hasNext()) {
          Department department = departments.next();
          dbm.getDatabase().deleteObject(department);
        }
      }
    
      @Test
      public void 一件load_ClassとSql条件() throws Exception {
        Department department = dbm.loadObject(Department.class,
            "where :departmentId = '" + d1Id + "'");
        assertEquals(d1Id, department.getDepartmentId());
        assertEquals(3, department.getMembers().size());
      }
    
      @Test
      public void 一件load_ClassとSql条件とパラメタ() throws Exception {
        Department department = dbm.loadObject(Department.class,
            "where :name like ?", "%1");
        assertEquals(d1Id, department.getDepartmentId());
      }
    
      @Test
      public void 一件load_Object() throws Exception {
        Department department = dbm.loadObject(new Department("%1"));
        assertEquals(d1Id, department.getDepartmentId());
      }
    
      @Test
      public void 全件取得() throws Exception {
        Collection<Department> departments = dbm.loadObjects(
            new ArrayList<Department>(), Department.class);
        assertEquals(3, departments.size());
        Collection<Member> members = dbm.loadObjects(new ArrayList<Member>(),
            Member.class);
        assertEquals(5, members.size());
      }
    
      @Test
      public void 複数件load_ClassとSql条件とパラメタ() throws Exception {
        Collection<Department> departments = dbm.loadObjects(
            new ArrayList<Department>(), Department.class,
            "where :name like ?", "dep%");
        assertEquals(3, departments.size());
      }
    
      @Test
      public void transactionManagerを使う() throws Exception {
        TransactionManager transaction = new TransactionManager(dbm) {
          Collection<Department> departments;
          final String sql = "where :name like 'dep%'";
    
          public void run() throws JPersistException { // 最初は3件。
            departments =
    
            dbm.loadObjects(new ArrayList<Department>(), Department.class,
                sql);
            assertEquals(3, departments.size());
    
            new Department("department_a").save(this);
            commit(); // 1件追加したから4件のはず。
            departments = loadObjects(Department.class, sql);
            assertEquals(4, departments.size());
    
            new Department("department_b").save(this); // さらに1件追加したから5件のはず。
            departments = loadObjects(Department.class, sql);
            assertEquals(5, departments.size());
    
            rollback(); // rollbackしたから4件のはず。
            departments = loadObjects(Department.class, sql);
            assertEquals(4, departments.size());
          }
        };
        transaction.executeTransaction();
      }
    
      @Test
      public void 一件delete() throws Exception {
        Department department = dbm.loadObject(Department.class,
            "where :departmentId = '" + d2Id + "'");
        dbm.deleteObject(department);
    
        Collection<Department> departments = loadObjects(Department.class);
        assertEquals(2, departments.size()); // delete cascadeでmemberも減っているはず。
        Collection<Member> members = loadObjects(Member.class);
        assertEquals(3, members.size());
      }
      
      <T> Collection<T> loadObjects(Class<T> c) throws JPersistException {
        return dbm.loadObjects(new ArrayList<T>(), c);
      }
    
      <T> Collection<T> loadObjects(Class<T> c, String sql)
          throws JPersistException {
        return dbm.loadObjects(new ArrayList<T>(), c, sql);
      }
    }
    
サンプルを元に単純な例を試すとこんなカンジに使うことになる。ModelがPOJOでないのが引っかかるけど、かなり簡単。Modelに[「get|set]Associations()」を追加するのがポイント。 ちなみに、注意点として「Modelにプリミティブな型を使わない」といぅこと!プリミティブな型はnullを表現できないため、自動的に関連先を取得する時のSQLの条件にプリミティブなフィールドが含まれていまい、正しく関連先が取得できません!俺ハマったよ! この状態で、SingleTableInheritanceを試そうとしたけど、PDFのドキュメントにある「jpersist.interface.SingleInheritance」が存在しなかったりで苦戦中。また後日チャレンジする。

2008年1月10日木曜日

色々リリース、jPersistとは何ぞや?

色々リリース

年始からのモノをまとめて。

jPersistとは何ぞ?

中の人の説明を見ると、ActiveRecordパターンのO/RMapperのよぅだ。ActiveRecordパターンのORMっていうとactiveobjectsくらいしか知らなかったけど、こっちはまだ先月0.7がリリースされたばかりで完成度は高いとは言えないと思われる。それに比べて、今回取り上げたjPersistは3.0とな。なんで今まで知らなかったのか自分でもワカランが、情報収集能力が低いって事なんだろな。説明を読んでみると、ActiveRecordパターンを実現するJDBCラッパって事ですな。ちなみに、ActiveRecordパターンの勉強にはActiveRecord Tutorialという25分間のムービーがあり、これがめちゃわかりやすかった記憶がある。だが、今の自分のUbuntuマシンでは音が出ない&動画再生を開始した瞬間にプレイヤが落ちるという現象が出るため見ることができなかった。無念だ。

Blogged with Flock