本文へジャンプ

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む


お客様が developerWorks に初めてサインインすると、プロフィールが作成されます。プロフィールで選択した情報は公開されますが、いつでもその情報を編集できます。お客様の姓名(非表示設定にしていない限り)とディスプレイ・ネームは、投稿するコンテンツと一緒に表示されます。

送信されたすべての情報は安全です。

  • 閉じる [x]

developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む


送信されたすべての情報は安全です。

  • 閉じる [x]

多忙な Java 開発者のための db4o ガイド: 単純なオブジェクトを越える

構造化オブジェクトを db4o を使って作成し、更新し、そして削除する

Ted Neward, Principal, Neward & Associates
Ted Neward は、Neward & Associates の代表として、Java や .NET、XML サービスなどのプラットフォームに関するコンサルティング、助言、指導、講演を行っています。彼はワシントン州シアトルの近郊に在住です。

概要: 前回までは、db4o の中でオブジェクトを作成したり操作したりすることはとても簡単に見えました。実際のところ、少し簡単すぎるかもしれません。今回の記事では、熱狂的な db4o 支持者である Ted Neward が、単純なオブジェクトが、構造化オブジェクト (つまりオブジェクトを参照するオブジェクト) になった場合に何が起こるのか、また無限再帰やカスケーディング動作、参照整合性などの問題が発生した場合に何が起こるかについて説明します。

このシリーズの他の記事を見る

日付:  2007年 6月 26日
レベル:  初級 この記事の原文:  英語
アクティビティー: 2272 ビュー
お気軽にご意見・ご感想をお寄せください: 


この「多忙な Java 開発者のための db4o ガイド」シリーズの前回までは、db4o を使ってマッピング・ファイルに頼らずに Java オブジェクトを保管するためのさまざまな方法について説明してきました。オブジェクト・リレーショナル・マッピングを使わずに済むことは、ネイティブ・オブジェクト・データベースを使う上での (核心ではないかもしれませんが) 利点の 1 つです。しかし、これを示すために私が使用したモデルは、非現実的なほど単純なものでした。大部分のエンタープライズ・システムでは、非常に複雑なオブジェクト (構造化オブジェクトとしても知られています) を作成したり操作したりする必要があります。そこでこの記事では少し方向を変え、構造化オブジェクトの作成について説明します。

構造化オブジェクトというのは、要するに他のオブジェクトに対する参照を持つオブジェクトのことです。db4o では、構造化オブジェクトに対して通常のすべての CRUD 操作を行えますが、そのために少し複雑になることは避けられません。この記事では、そのように複雑になる主な原因のいくつか (無限再帰やカスケーディング動作、参照整合性など) を探り、次回の記事で、構造化オブジェクトの高度な処理方法について解説します。さらに、クラス・ライブラリーと db4o の API の両方をテストできる、あまり知られていないテスト手法、エクスプローラー・テストを紹介します。

単純なオブジェクトから構造化オブジェクトへ

リスト 1 は、これまで db4o を紹介する中で使用してきた単純な Person クラスを改めて要約したものです。


リスト 1. Person
                
package com.tedneward.model;

public class Person
{
    public Person()
    { }
    public Person(String firstName, String lastName, int age, Mood mood)
    {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
        this.mood = mood;
    }
    
    public String getFirstName() { return firstName; }
    public void setFirstName(String value) { firstName = value; }
    
    public String getLastName() { return lastName; }
    public void setLastName(String value) { lastName = value; }
    
    public int getAge() { return age; }
    public void setAge(int value) { age = value; }
    
    public Mood getMood() { return mood; }
    public void setMood(Mood value) { mood = value; }

    public String toString()
    {
        return 
            "[Person: " +
            "firstName = " + firstName + " " +
            "lastName = " + lastName + " " +
            "age = " + age + " " + 
            "mood = " + mood +
            "]";
    }
    
    public boolean equals(Object rhs)
    {
        if (rhs == this)
            return true;
        
        if (!(rhs instanceof Person))
            return false;
        
        Person other = (Person)rhs;
        return (this.firstName.equals(other.firstName) &&
                this.lastName.equals(other.lastName) &&
                this.age == other.age);
    }
    
    private String firstName;
    private String lastName;
    private int age;
    private Mood mood;
}

OODBMS システムの String

これまでの記事の例の中で使用してきた Person 型が、 String をフィールドとして使っていたことを思い出してください。Java と .NET では String はオブジェクト型であり、 Object から継承します。これは矛盾しているように見えるかもしれません。実際は、db4oを含む大部分の OODBMS システムでは、(特に String の持つ不変性のため) String を他のオブジェクトとは異なる方法で扱います。

この単純な Person クラスは、db4o での基本的な保管やクエリー、取得などの操作を紹介するための例としては適切でしたが、実際のエンタープライズ・プログラミングの複雑さには対応できません。例えば、データベースの中の Person が家の住所を含むことは珍しくないでしょう。そのうちの何人かは、配偶者や、場合によっては子供がいるかもしれません。

ここで、データベースに「Spouse (配偶者)」用のフィールドを追加したいと思います。これはつまり、Spouse オブジェクトを参照するように Person を拡張するということです。何らかのビジネス・ルールに対応することを考えると、適切に変更された Gender 列挙型と、equals() メソッドもコンストラクターに追加する必要があります。リスト 2 の Person 型には、spouse フィールドと、適切な get/set メソッドのペアが、いくつかのビジネス・ルールが付加された形で存在しています。


リスト 2. この人は結婚できる人なのか
                
package com.tedneward.model;
public class Person {
    // . . .

    public Person getSpouse() { return spouse; }
    public void setSpouse(Person value) { 
        // A few business rules
        if (spouse != null)
            throw new IllegalArgumentException("Already married!");
        
        if (value.getSpouse() != null && value.getSpouse() != this)
            throw new IllegalArgumentException("Already married!");
            
        spouse = value; 
        
        // Highly sexist business rule
        if (gender == Gender.FEMALE)
            this.setLastName(value.getLastName());

        // Make marriage reflexive, if it's not already set that way
        if (value.getSpouse() != this)
            value.setSpouse(this);
    }
    
    private Person spouse;    
}

リスト 3 は、結婚可能な 2 人の Person を作成するコードを示しています。これは、ほとんど皆さんが想像する通りのものです。


リスト 3. 教会に行き、結婚します
                
import java.util.*;
import com.db4o.*;
import com.db4o.query.*;
import com.tedneward.model.*;

public class App
{
    public static void main(String[] args)
        throws Exception
    {
        ObjectContainer db = null;
        try
        {
            db = Db4o.openFile("persons.data");

            Person ben = new Person("Ben", "Galbraith", 
                Gender.MALE, 29, Mood.HAPPY);
            Person jess = new Person("Jessica", "Smith", 
                Gender.FEMALE, 29, Mood.HAPPY);
            
            ben.setSpouse(jess);
            
            System.out.println(ben);
            System.out.println(jess);
            
            db.set(ben);
            
            db.commit();
            
            List<Person> maleGalbraiths = 
                db.query(new Predicate<Person>() {
                    public boolean match(Person candidate) {
                        return candidate.getLastName().equals("Galbraith") &&
                                candidate.getGender().equals(Gender.MALE);
                    }
                });
            for (Person p : maleGalbraiths)
            {
                System.out.println("Found " + p);
            }
        }
        finally
        {
            if (db != null)
                db.close(); 
        }
    }
}

複雑さがむさくるしい頭を持ち上げる

ここでは、好ましくなさそうなビジネス・ルールとは別に、いくつか重要なことが行われています。第 1 に、ben オブジェクトがデータベースに保存されると、OODBMS は明らかに、単に 1 つのオブジェクトを保管する以上のことをします。逆に ben オブジェクトをデータベースから取得すると、関連付けられた配偶者は、保管されているだけではなく、自動的に取得されるのです。

このシリーズについて

過去 10 年ほど、情報の保存と取得はほとんど RDBMS と同義語でしたが、最近それが変わり始めています。特に Java 開発者は、いわゆるオブジェクトとリレーショナルとのミスマッチに不満を募らせており、それを解決するためのソリューションにも我慢できなくなっています。そのため、また有効な代替手段が現れてきたことにより、オブジェクトのパーシスタンスと取得に対する新たな関心が生まれつつあります。 「多忙な Java 開発者のための db4o ガイド」では db4o を紹介します。db4o はオープンソースのデータベースであり、今日のオブジェクト指向の言語やシステム、考え方を活用しています。 db4o のホームページを訪れ、今すぐ db4o をダウンロードしてください。この記事で説明する例を追うためには、このダウンロードが必要です。

これは、考えてみると少し恐ろしい意味合いを持っています。ここから、OODBMS が無限再帰シナリオをどう回避しているのかを理解することは不可能ではありませんが、それよりも、ある 1 つのオブジェクトが、それぞれ独自のオブジェクトを参照する何十、あるいは何百、何千のオブジェクト参照を持つシナリオを考えると、もっと恐ろしくなります。例えば、このモデルが子供と親、等々を表現するとしたらどうなるかを少し考えてみてください。データベースから 1 つの Person を取得しようとすると、歴史の起源以来のすべての人間を取得することになっても不思議はありません。これでは、膨大なオブジェクトをネットワーク経由で引き出すことになります。

幸い、初期の OODBMS を除くすべての OODBMS は、こうした懸念事項に対応しており、db4o もその例外ではありません。

db4o のエクスプローラー・テスト

db4o の、この面を探るのは面倒な作業ですが、ここでは私の友人が教えてくれた方法、エクスプローラー・テスト (exploration test) を紹介しましょう。(私の知る限り最初にこの言葉を作り出した人である、Stu Halloway 氏に感謝します。) 一言で言えば、エクスプローラー・テストというのは、対象のライブラリーをテストするだけではなく API も調べ、ライブラリーが想定通り動作することを確認するために作成された一連のユニット・テストなのです。この方法の有益な副次的効果として、ライブラリーの将来のバージョンをエクスプローラー・テスト・コードに入れてコンパイルし、テストすることができます。もしコードがコンパイルできない、あるいはエクスプローラー・テストのすべてにパスすることができない場合には、そのライブラリーは明らかに後方互換ではありません。それを、実動システムで使う前に知ることができるのです。

db4o の API をエクスプローラー・テストすることで、データベースを作成してそこに Person データを追加する「before」メソッドを設定することができ、またデータベースを破棄してテスト中にフォルス・ポジティブが起きる可能性をなくす「after」メソッドを設定することができます。これがないと、毎回忘れずに persons.data ファイルを手動で削除しなければなりません。私は正直なところ、それを API を調べるたびに忘れずに行えるかどうか、自分自身を信頼できません。

ここでの db4o のエクスプローラー・テストでは、JUnit 4 テスト・ライブラリーをコンソール・モードで使います。何もテストを作成していない状態では、StructuredObjectTest クラスはリスト 4 に示すようなものです。


リスト 4. db4o の API を予備テストする
                
import java.io.*;
import java.util.*;
import com.db4o.*;
import com.db4o.query.*;
import com.tedneward.model.*;

import org.junit.Before;
import org.junit.After; 
import org.junit.Ignore; 
import org.junit.Test; 
import static org.junit.Assert.*;

public class StructuredObjectsTest
{
    ObjectContainer db;

    @Before public void prepareDatabase()
    {
        db = Db4o.openFile("persons.data");

        Person ben = new Person("Ben", "Galbraith", 
            Gender.MALE, 29, Mood.HAPPY);
        Person jess = new Person("Jessica", "Smith", 
            Gender.FEMALE, 29, Mood.HAPPY);
    
        ben.setSpouse(jess);
    
        db.set(ben);
    
        db.commit();
    }
    
    @After public void deleteDatabase()
    {
        db.close();
        new File("persons.data").delete();
    }


    @Test public void testSimpleRetrieval()
    {
        List<Person> maleGalbraiths = 
            db.query(new Predicate<Person>() {
                public boolean match(Person candidate) {
                    return candidate.getLastName().equals("Galbraith") &&
                            candidate.getGender().equals(Gender.MALE);
                }
            });
            
        // Should only have one in the returned set
        assertEquals(maleGalbraiths.size(), 1);

        // (Shouldn't display to the console in a unit test, but this is an
        // exploration test, not a real unit test)
        for (Person p : maleGalbraiths)
        {
            System.out.println("Found " + p);
        }
    }
}

当然ながら、このテスト・スイートに対して JUnit テスト・ランナーを実行すると、コンソールあるいは GUI どちらのテスト・ランナーを使ったかによって、想定した出力である、「 . 」あるいは緑のバーが作成されます。通常、コンソールにデータを書き込むことは好ましくないですが (つまりデータは目ではなくアサーションを使って検証すべきです)、エクスプローラー・テストの場合には、何を取得できるのかを適当なデータをアサートする前に調べるための適切な方法であることに注意してください。もし他のものがすべて失敗したら、いつでも System.out.println コールをコメントアウトすることができます。(db4o の API の他の面をテストするために必要と思えるものを、自由にテストに追加してください。)

ここから先では、コード・サンプルは (メソッドのシグニチャーに対する @Test 注釈からわかるように) リスト 4 に示すテスト・スイート内部のテスト・メソッドだという前提で話を進めます。


構造化オブジェクトを保管し、取得する

構造化オブジェクトを保管するために必要なことの大部分は、これまでに行ったことと同じです。つまりオブジェクトに対して db.set() をコールすると、後は OODBMS が行ってくれます。set() をコールする対象のオブジェクトは、あまり重要ではありません。その理由は、OODBMS は OID (object identifier) によってオブジェクトを追跡するため (「多忙な Java 開発者のための db4o ガイド: クエリー、更新、そして ID」を参照)、同じオブジェクトを 2 度保管する方法を知らないからです。

構造化オブジェクトを取得することを考えると身の毛がよだちます。もし、(QBE によって、あるいはネイティブ・クエリーによって) 取得されるオブジェクトがいくつかのオブジェクト参照を持っており、またそうしたオブジェクトが、それぞれいくつかのオブジェクト参照を持っているとしたらどうなるでしょう。これは一種の悪徳ネズミ講のようなものではないでしょうか。

無限再帰を回避する

大部分の開発者は無限再帰に対して、最初は「絶対そんな風にしているはずはないのですが」というような反応をしますが、無限再帰はまさに (ある意味で)、構造化オブジェクトを db4o が取得する方法そのものです。実際、この種の動作は大部分のプログラマーが望む動作そのものです。なぜなら、私達がオブジェクトを探す際には一般的に、作成したオブジェクトが「すぐそこにある」ことを期待するからです。同時に、当然ながら私達は、世界全体をネットワークから取得したいとは思いません (少なくとも一度に取得したいとは思いません)。

db4o は妥協として、取得するオブジェクトの数を、アクティベーションの深さ (activation depth) と呼ばれるメカニズムを使って制限します (アクティベーションの深さは、オブジェクト・グラフのどこまで下がってオブジェクトを取得するのか、そのレベル数を示します)。つまりアクティベーションの深さは、db4o がトラバースしてクエリーの一部として返す、(ルート・オブジェクトから識別可能な) 参照の数をカウントしたものです。前の場合で Ben を取得する際に Jessica も取得するためには (1 つの参照をトラバースすれば Jessica を取得できるので)、デフォルトのアクティベーションの深さ (5) で十分です。Ben から 5 つの参照ホップよりも遠いオブジェクトは取得されず、それらのオブジェクトの参照はヌルのままです。そうすると今度は、(ObjectContainer コンテナーに対して activate() メソッドを使うことで) これらのオブジェクトをデータベースから明示的にアクティベートするのは私の仕事になります。

デフォルトのアクティベーションの深さを変更したい場合には、(db.configure() から返される) Configuration クラスに対して db4o の activationDepth() メソッドを使ってデフォルトを他の値に変更することで、きめ細かな変更を行うことができます。あるいは、アクティベーションの深さをクラスごとに設定することもできます。リスト 5 では、ObjectClass を使って Person 型のアクティベーションの深さを設定しています。


リスト 5. ObjectClass を使ってアクティベーションの深さを設定する
                
// See ObjectClass for more info
Configuration config = Db4o.configure();
ObjectClass oc = config.objectClass("com.tedneward.model.Person");
oc.minimumActivationDepth(10);


構造化オブジェクトを更新する

更新も、懸念事項の 1 つです。もし、グラフの中の、ある 1 つのオブジェクトを更新し、それを明示的に設定しなかったらどうなるのでしょう。初めて set() をコールすると、保管されているオブジェクトを参照する従属オブジェクトが保管されるのと同じように、あるオブジェクトが ObjectContainer に渡されると、db4o はその参照をトラバースし、見つかったオブジェクトもデータベースの中に保管します (リスト 6)。


リスト 6. 参照されるオブジェクトを更新する
                
@Test public void testDependentUpdate()
{
    List<Person> maleGalbraiths = 
        db.query(new Predicate<Person>() {
            public boolean match(Person candidate) {
                return candidate.getLastName().equals("Galbraith") &&
                        candidate.getGender().equals(Gender.MALE);
            }
        });
        
    Person ben = maleGalbraiths.get(0);
        
    // Happy birthday, Jessica!
    ben.getSpouse().setAge(ben.getSpouse().getAge() + 1);

    // We only have a reference to Ben, so store that and commit
    db.set(ben);
    db.commit();

    // Find Jess, make sure she's 30
    Person jess = (Person)db.get(
            new Person("Jessica", "Galbraith", null, 0, null)).next();
    assertTrue(jess.getAge() == 30);
}

jess オブジェクトは変更されましたが、ben オブジェクトは jess への参照を保持したままです。従ってメモリー内の jess Person に対して更新された変更は、データベースに対しても一貫して持続されます。

いや、実はそうなりません。私はまったく嘘をついていました。

フォルス・ポジティブをテストする

実は、これはエクスプローラー・テストに失敗し、フォルス・ポジティブを生ずる 1 つの領域なのです。ドキュメンテーションからは明白ではありませんが、ObjectContainer はアクティベートされたオブジェクトのキャッシュを維持します。そのため、リスト 6 のテストがコンテナーから Jessica オブジェクトを取得する際には、実際にディスクに書き込まれたデータではなく、その変更を含むメモリー内オブジェクトを返します。これによって今度は、ある型に対するデフォルトの更新の深さ (update depth) が 1 であるという事実が隠されます。これはつまり、set() コールでは (Strings) を含む) プリミティブ値のみが保管されることを意味します。この動作の実際を見るためには、少しテストを変更する必要があります (リスト 7)。


リスト 7. フォルス・ポジティブをテストする
                
@Test(expected=AssertionError.class)
public void testDependentUpdate()
{
    List<Person> maleGalbraiths = 
        db.query(new Predicate<Person>() {
            public boolean match(Person candidate) {
                return candidate.getLastName().equals("Galbraith") &&
                        candidate.getGender().equals(Gender.MALE);
            }
        });
            
    Person ben = maleGalbraiths.get(0);
    assertTrue(ben.getSpouse().getAge() == 29);
    
    // Happy Birthday, Jessica!
    ben.getSpouse().setAge(ben.getSpouse().getAge() + 1);

    // We only have a reference to Ben, so store that and commit
    db.set(ben);
    db.commit();
        
    // Close the ObjectContainer, then re-open it
    db.close();
    db = Db4o.openFile("persons.data");

    // Find Jess, make sure she's 30
    Person jess = (Person)db.get(
            new Person("Jessica", "Galbraith", null, 0, null)).next();
    assertTrue(jess.getAge() == 30);
}

これを行うと、AssertionFailure が取得されます。これでは私が先ほど、オブジェクトを更新すると、その更新が順次グラフの下の方にカスケーディングしていく、と言ったことが嘘ということになります。(@Test 注釈に対してスローされると想定されるクラス型を expected 値に設定することで、この失敗を JUnit に事前に想定させることができます。)

カスケーディング動作を設定する

キャッシュされたオブジェクトを db4o が暗黙的に処理せず、単純に返すだけという点は、議論の余地のあるところです。大部分のプログラマーは、この動作は破壊的であり直感的でないと考えるか、あるいはこれこそ OODBMS が行うべき動作だと考えるかのいずれかです。ここで重要なのは、それぞれの立場のメリットには深入りせず、データベースのデフォルトの動作を理解し、その変更方法を知ることです。リスト 8 では ObjectClass.setCascadeOnUpdate() メソッドを使って、ある特定の型に対する db4o のデフォルトの更新動作を変更しています。ただし、ObjectContainer を開く前に、このメソッドを「真」に設定する必要があったことに注意してください。リスト 8 は、変更された、正しいカスケーディング・テストを示しています。


リスト 8. カスケーディング動作を「真」に設定する
                
@Test
public void testWorkingDependentUpdate()
{
    // the cascadeOnUpdate() call must be done while the ObjectContainer
    // isn't open, so close() it, setCascadeOnUpdate, then open() it again
    db.close();
    Db4o.configure().objectClass(Person.class).cascadeOnUpdate(true);
    db = Db4o.openFile("persons.data");

    List<Person> maleGalbraiths = 
        db.query(new Predicate<Person>() {
            public boolean match(Person candidate) {
                return candidate.getLastName().equals("Galbraith") &&
                        candidate.getGender().equals(Gender.MALE);
            }
        });
           
    Person ben = maleGalbraiths.get(0);
    assertTrue(ben.getSpouse().getAge() == 29);
        
    // Happy Birthday, Jessica!
    ben.getSpouse().setAge(ben.getSpouse().getAge() + 1);

    // We only have a reference to Ben, so store that and commit
    db.set(ben);
    db.commit();
        
    // Close the ObjectContainer, then re-open it
    db.close();
        
    db = Db4o.openFile("persons.data");

    // Find Jess, make sure she's 30
    Person jess = (Person)db.get(
            new Person("Jessica", "Galbraith", null, 0, null)).next();
    assertTrue(jess.getAge() == 30);
}

カスケーディング動作は、更新用に設定できるだけではなく、取得用に設定する (そして「無限の」アクティベーションの深さを作成する) ことも、削除用に設定することもできます。削除用の設定については、洗練された新しい Person オブジェクトに対する操作として、最後に説明します。


構造化オブジェクトを削除する

オブジェクトをデータベースから削除するための操作は、取得や更新の場合と同じです。あるオブジェクトが削除される際には、デフォルトでは、そのオブジェクトが参照するオブジェクトはどれも削除されません。これも、一般的には望ましい動作です (リスト 9)。


リスト 9. 構造化オブジェクトを削除する
                
@Test
public void simpleDeletion()
{
  Person ben = (Person)db.get(new Person("Ben", "Galbraith", null, 0, null)).next();
  db.delete(ben);
        
  Person jess = (Person)db.get(new Person("Jessica", "Galbraith", null, 0, null)).next();
  assertNotNull(jess);
}

しかし場合によると、削除するオブジェクトに参照されているオブジェクトも強制的に削除したいことがあります。アクティベーションと更新の場合と同じく、この動作は Configuration クラスを呼び出すことで設定することができます (リスト 10)。


リスト 10. Configuration.setCascadeOnDelete()
                
@Test
public void cascadingDeletion()
{
    // the cascadeOnUpdate() call must be done while the ObjectContainer
    // isn't open, so close() it, setCascadeOnUpdate, then open() it again
    db.close();
    Db4o.configure().objectClass(Person.class).cascadeOnDelete(true);
    db = Db4o.openFile("persons.data");

    Person ben = 
        (Person)db.get(new Person("Ben", "Galbraith", null, 0, null)).next();
    db.delete(ben);
        
    ObjectSet<Person> results = 
        db.get(new Person("Jessica", "Galbraith", null, 0, null));
    assertFalse(results.hasNext());
}

ただしこれは、注意して行う必要があります。なぜなら、これはカスケードで削除されるオブジェクトを参照する他のすべてのオブジェクトが、今やヌルへの参照を保持することを意味するからです。つまり db4o オブジェクト・データベースには、参照されるオブジェクトが削除されるのを防止するための参照整合性の概念がありません。(参照整合性は db4o では一般的に要求される機能であり、開発チームは、今後のバージョンでこの機能を追加する方法を検討中だと聞いています。リレーショナル・データベースの場合でさえ、整合性を破ることが実際には望ましい場合もあることを考えると、鍵となるのは、db4o を使用する開発者にとって POLS (Principle Of Least Surprise: 驚き最小の法則) に反しない方法で、この機能を追加することになるでしょう。)


まとめ

今回の記事は、このシリーズの分岐点です。前回までは、すべての例は非常に単純なオブジェクトに基づくものでした。それらの例はアプリケーションの観点からは非現実的ですが、保管されるオブジェクトではなく OODBMS の理解に焦点を絞るためには適切でした。参照によって保持される関連オブジェクトを db4o のような OODBMS がどう保管するのかを理解することは、簡単ではありません。しかし幸いなことに、いったん動作が完全に説明され、それを理解できれば、単にその動作を考慮に入れてコードの調整を始めればよいだけです。

この記事では、db4o のオブジェクト・モデルを考慮して複雑なコードを調整するための最初の例をいくつか見てきました。構造化オブジェクトに対して単純な CRUD 操作を行う方法を学び、そうする中で、必然的に発生する問題とその回避方法をいくつか見ました。

しかしここまでは、構造化オブジェクトの例と言っても、それらに対する直接の参照を操作したのみ、という意味で、ある程度単純なものでした。多くのカップルが学ぶように、結婚してしばらくすると、子供の話題が出るようになります。このシリーズの次回の記事では、ben オブジェクトとjess オブジェクトとでうまくいっている状況に何人かの子供を組み入れると何が起こるのかを調べながら、db4o で構造化オブジェクトを作成して操作するための方法をさらに詳しく探ります。


参考文献

学ぶために

製品や技術を入手するために

  • Java プログラミングと .NET 専用のオープンソースのデータベース、 db4o をダウンロードしてください。

議論するために

著者について

Ted Neward は、Neward & Associates の代表として、Java や .NET、XML サービスなどのプラットフォームに関するコンサルティング、助言、指導、講演を行っています。彼はワシントン州シアトルの近郊に在住です。

不正使用の報告のヘルプ

不正使用の報告

ありがとうございます。 このエントリーは、モデレーターの注目フラグが設定されました。


不正使用の報告のヘルプ

不正使用の報告

不正使用の報告の送信に失敗しました。


developerWorks: サイン・イン


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 利用条件

 


お客様が developerWorks に初めてサインインすると、プロフィールが作成されます。 プロフィールで選択した情報は公開されますが、いつでもその情報を編集できます。 お客様の姓名(非表示設定にしていない限り)とディスプレイ・ネームは、投稿するコンテンツと一緒に表示されます。

表示名をお選びください

developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

(半角英数字で3文字以上31文字以下にする必要があります)


「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 利用条件

 


この記事を評価する

コメント

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Java technology
ArticleID=242151
ArticleTitle=多忙な Java 開発者のための db4o ガイド: 単純なオブジェクトを越える
publish-date=06262007
author1-email=ted@tedneward.com
author1-email-cc=

タグ

Help
このタグで、My developerWorks のすべてのタイプのコンテンツを見つけるために検索フィールドを使用します。

スライダーバーを使用することで、より多く(少なく)タグを表示します。

人気のタグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するトップのタグを表示します。

マイ・タグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するお客様ご自身のタグを表示します。

このタグで、My developerWorks のすべてのタイプのコンテンツを見つけるために検索フィールドを使用します。人気のタグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するトップのタグを表示します。マイ・タグは、この特定のコンテンツ・ゾーン(例えば、Java テクノロジー、Linux や WebSphere など)に対するお客様ご自身のタグを表示します。