db4o 物件資料庫的優勢在於能直接持久化物件圖,無需 ORM 映射。本文透過擴充 Person 類別,示範如何處理陣列(固定數量地址)與集合(動態子女清單)的持久化、查詢與關聯維護。
public class Address {
private String street, city, state, zip;
// 建構子、getter/setter、equals/hashCode/toString 略
}
public class Person {
private String firstName, lastName;
private Gender gender;
private int age;
private Mood mood;
private Person spouse;
private Address[] addresses = new Address[3]; // 固定三個地址:住家、公司、渡假屋
private List<Person> children = new ArrayList<>(); // 動態子女清單
private Person mother, father; // 雙向父母關聯
// 業務方法:生小孩(含生理/倫理規則驗證)
public Person haveBaby(String name, Gender gender) {
if (this.gender == Gender.MALE) throw new UnsupportedOperationException("Biological impossibility!");
if (spouse == null) throw new UnsupportedOperationException("Ethical impossibility!");
Person child = new Person(name, this.lastName, gender, 0, Mood.CRANKY);
child.father = spouse; child.mother = this;
children.add(child); spouse.children.add(child);
return child;
}
// getter/setter、equals/toString 略
}
@Before
public void prepareDatabase() {
db = Db4o.openFile("persons.data");
Person bruce = new Person("Bruce", "Tate", Gender.MALE, 29, Mood.HAPPY);
Person maggie = new Person("Maggie", "Tate", Gender.FEMALE, 29, Mood.HAPPY);
bruce.setSpouse(maggie);
bruce.setHomeAddress(new Address("5 Maple Drive", "Austin", "TX", "12345"));
bruce.setWorkAddress(new Address("5 Maple Drive", "Austin", "TX", "12345"));
bruce.setVacationAddress(new Address("10 Wanahokalugi Way", "Oahu", "HA", "11223"));
Person kayla = maggie.haveBaby("Kayla", Gender.FEMALE); kayla.setAge(8);
Person julia = maggie.haveBaby("Julia", Gender.FEMALE); julia.setAge(6);
db.store(bruce); // 遞迴持久化整個物件圖
db.commit();
}
db4o 自動維護物件參考完整性,跨查詢取得的物件仍保持關聯:
// 查詢地址
List<Person> maleTates = db.query(new Predicate<Person>() {
public boolean match(Person c) { return "Tate".equals(c.getLastName()) && c.getGender()==Gender.MALE; }
});
assertTrue(bruce.getHomeAddress().equals(new Address("5 Maple Drive", "Austin", "TX", "12345")));
// 查詢子女
for (Person child : bruce.getChildren()) { ... } // 正確取得 Kayla、Julia
// 查詢所有女性
List<Person> girls = db.query(new Predicate<Person>() {
public boolean match(Person c) { return c.getGender()==Gender.FEMALE; }
}); // 包含 Maggie、Kayla、Julia
// 跨查詢驗證雙向關聯
Person maggie = db.get(new Person("Maggie", "Tate", Gender.FEMALE, 0, null)).next();
Person julia = db.get(new Person("Julia", "Tate", Gender.FEMALE, 0, null)).next();
assertTrue(julia.getMother() == maggie); // 同一物件實例
// 更新:修改子女年齡後存儲父母即可級聯更新
kayla.setAge(kayla.getAge() + 1);
db.store(maggie);
db.commit();
// 重新開啟資料庫驗證
db = Db4o.openFile("persons.data");
assertEquals(kaylasNewAge, db.get(...).next().getAge());
// 刪除:級聯刪除會移除所有參考,導致父母的 children 清單出現 null
// 需謹慎設計刪除策略,避免殘留無效參考