科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道面向Java开发人员db4o指南:数组和集合 (2)

面向Java开发人员db4o指南:数组和集合 (2)

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

面向Java开发人员db4o指南:数组和集合

作者:baocl 来源:赛迪网技术社区 2007年10月29日

关键字: 集合 数组 db4o

  • 评论
  • 分享微博
  • 分享邮件

清单 3. 幸福家庭测试



@Test public void testTheModel()
{
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);

Person kayla = maggie.haveBaby("Kayla", Gender.FEMALE);

Person julia = maggie.haveBaby("Julia", Gender.FEMALE);

assertTrue(julia.getFather() == bruce);
assertTrue(kayla.getFather() == bruce);
assertTrue(julia.getMother() == maggie);
assertTrue(kayla.getMother() == maggie);

int n = 0;
for (Iterator<Person> kids = bruce.getChildren(); kids.hasNext(); )
{
Person child = kids.next();

if (n == 0) assertTrue(child == kayla);
if (n == 1) assertTrue(child == julia);

n++;
}
}


目前一切尚好。所有方面都能通过测试,包括小孩 ArrayList 的使用中的长嗣身份。但是,当增加 @Before 和 @After 条件,以便用我的测试数据填充 db4o 数据库时,事情开始变得更有趣。


清单 4. 将孩子发送到数据库



@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.set(bruce);

db.commit();
}



注意,存储整个家庭所做的工作仍然不比存储单个 Person 对象所做的工作多。您可能还记得,在上一篇文章中,由于存储的对象具有递归的性质,当把 bruce 引用传递给 db.set() 调用时,从 bruce 可达的所有对象都被存储。不过眼见为实,让我们看看当运行那个简单的探察测试时,实际上会出现什么情况。首先,测试当调用随 Person 存储的各种 Address 时,是否可以找到它们。然后,测试是否孩子们也被存储。


清单 5. 搜索住房和家庭



@Test public void testTheStorageOfAddresses()
{
List<Person> maleTates =
db.query(new Predicate<Person>() {
public boolean match(Person candidate) {
return candidate.getLastName().equals("Tate") &&
candidate.getGender().equals(Gender.MALE);
}
});
Person bruce = maleTates.get(0);

Address homeAndWork =
new Address("5 Maple Drive", "Austin",
"TX", "12345");
Address vacation =
new Address("10 Wanahokalugi Way", "Oahu",
"HA", "11223");

assertTrue(bruce.getHomeAddress().equals(homeAndWork));
assertTrue(bruce.getWorkAddress().equals(homeAndWork));
assertTrue(bruce.getVacationAddress().equals(vacation));
}

@Test public void testTheStorageOfChildren()
{
List<Person> maleTates =
db.query(new Predicate<Person>() {
public boolean match(Person candidate) {
return candidate.getLastName().equals("Tate") &&
candidate.getGender().equals(Gender.MALE);
}
});
Person bruce = maleTates.get(0);

int n = 0;
for (Iterator<Person> children = bruce.getChildren();
children.hasNext();
)
{
Person child = children.next();

System.out.println(child);

if (n==0) assertTrue(child.getFirstName().equals("Kayla"));
if (n==1) assertTrue(child.getFirstName().equals("Julia"));

n++;
}
}



理解关系 

您可能会感到奇怪,清单 5 中显示的基于 Collection 的类型(ArrayList)没有被存储为 Person 类型的 “dependents”,而是被存储为一个成熟的对象。这还说得过去,但是当对对象数据库中的 ArrayList 运行一个查询时,它可能,有时候也确实会导致返回奇怪的结果。由于目前数据库中只有一个 ArrayList,所以还不值得运行一个探察测试,看看当对它运行一个查询时会出现什么情况。把这作为留给您的练习。

自然地,存储在一个集合中的 Person 也被当作数据库中的一级实体,所以在查询符合某个特定标准(例如所有女性 Person)的所有 Person 时,也会返回 ArrayList 实例中引用到的那些 Person,如清单 6 所示。


清单 6. 什么是 Julia?


@Test public void findTheGirls()
{
List<Person> girls =
db.query(new Predicate<Person>() {
public boolean match(Person candidate) {
return candidate.getGender().equals(Gender.FEMALE);
}
});
boolean maggieFound = false;
boolean kaylaFound = false;
boolean juliaFound = false;
for (Person p : girls)
{
if (p.getFirstName().equals("Maggie"))
maggieFound = true;
if (p.getFirstName().equals("Kayla"))
kaylaFound = true;
if (p.getFirstName().equals("Julia"))
juliaFound = true;
}

assertTrue(maggieFound);
assertTrue(kaylaFound);
assertTrue(juliaFound);
}


注意,对象数据库将尽量地使引用 “correct” — 至少在知道引用的情况下如此。例如,分别在两个不同的查询中检索一个 Person(也许是母亲)和检索另一个 Person(假设是女儿),仍然认为她们之间存在一个双向关系,如清单 7 所示。


清单 7. 保持关系的真实性


@Test public void findJuliaAndHerMommy()
{
Person maggie = (Person) db.get(
new Person("Maggie", "Tate", Gender.FEMALE, 0, null)).next();
Person julia = (Person) db.get(
new Person("Julia", "Tate", Gender.FEMALE, 0, null)).next();

assertTrue(julia.getMother() == maggie);
}


当然,您正是希望对象数据库具有这样的行为。还应注意,如果返回女儿对象的查询的激活深度被设置得足够低,那么对 getMother() 的调用将返回 null,而不是实际的对象。这是因为 Person 中的 mother 字段是相对于被检索的原本对象的另一个 “跳跃(hop)”。


更新和删除

至此,您已经看到了 db4o 如何存储和取出多个对象,但是对象数据库如何处理更新和删除呢?就像结构化对象一样,多对象更新或删除期间的很多工作都与管理更新深度有关,或者与级联删除有关。现在您可能已经注意到,结构化对象与集合之间有很多相似之处,所以其中某一种实体的特性也适用于另一种实体。如果将 ArrayList 看作 “另一种结构化对象”,而不是一个集合,就很好理解了。

所以,根据到目前为止您学到的东西,我应该可以更新数据库中的某一个女孩。而且,为了更新这个对象,只需将她父母中的一个重新存储到数据库中,如清单 8 所示。


清单 8. 生日快乐,Kayla!



@Test public void kaylaHasABirthday()
{
Person maggie = (Person) db.get(
new Person("Maggie", "Tate", Gender.FEMALE, 0, null)).next();
Person kayla = (Person) db.get(
new Person("Kayla", "Tate", Gender.FEMALE, 0, null)).next();

kayla.setAge(kayla.getAge() + 1);
int kaylasNewAge = kayla.getAge();

db.set(maggie);

db.close();

db = Db4o.openFile("persons.data");

kayla = (Person) db.get(
new Person("Kayla", "Tate", Gender.FEMALE, 0, null)).next();
assert(kayla.getAge() == kaylasNewAge);
}



对于多样性关系中的对象,其删除工作非常类似于上一篇文章介绍索的结构化对象的删除工作。只需注意级联删除,因为它对这两种对象可能都有影响。当执行级联删除时,将会从引用对象的每个地方彻底删除对象。如果执行一个级联删除来从数据库中删除一个 Person,则那个 Person 的母亲和父亲在其 children 集合中突然有一个 null 引用,而不是有效的对象引用。

查看本文来源
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章