顯示具有 db4o 標籤的文章。 顯示所有文章
顯示具有 db4o 標籤的文章。 顯示所有文章

2011年9月23日 星期五

db4o 物件的唯一性:disconnected objects 的概念與 web apps

db4o 在單一 object container 的環境下,在物件管理上會確保儲存在資料庫內的物件的唯一性。但是,若是啟用了 client-server 或是 session-container 的架構,則會變成多 object-container 的情況,因此同一個物件可能會在不同的 container 中有不同的 memory identity。這種情況在 web 環境下一定會發生。這時候就要借助額外的 ID,如 db4o 內建的內部 ID:UUID,或是自行產生 ID。

簡而言之,最重要的概念就是加入 EventRegistry,在建立時去檢查是否有 ID 已經存在:

// register 
IEventRegistry eventRegistry = EventRegistryFactory.ForObjectContainer(icontainer);
eventRegistry.Creating += delegate(object sender, CancellableObjectEventArgs args)
{
    if (args.Object is Article)
    {
        Article a = (Article)args.Object;
        if (a.HasDb4oID()) {                       
           // don't insert because Article is already
           // in the container
           args.Cancel();
           Article existing = LookupArticle(icontainer, a.Db4oID) as Article;
           // merge change
           existing.MergeChanges(a);
       } else {
           a.SetDb4oID(a.ArticleID);
       }
    }    
};

相關參考資料如下:

2009年6月28日 星期日

db4o client/server 模式

從 db4o 的 API 來看,要存取遠端資料庫伺服器跟本地端直接開啟資料庫伺服器以支援同時存取(concurrent transaction)的方法幾乎沒有甚麼不同。要使用同時存取,只要把原本開啟資料庫檔案的方式改換成開啟 db4o 伺服器的模式,並將其啟動於 port 0 即可(因而不需要任何的網路連線):
IObjectServer server = Db4oFactory.OpenServer("db.filename", 0);
try
{
    IObjectContainer client = server.OpenClient();
    // 讓 client 端做某些事情
    // ...
    client.Close();
}
finally
{
    server.Close();
}
在 db4o 中,client 端的 transaction 只處於 read commit(不過每個 client container 都維護一個 weak 參考快取,參考到它所有已知、參考到的物件)。要讓所有 client 端中未決的更新 comment 立即執行,我們可以明確的自伺服器中的更新已知的物件:
IObjectContainer client1 =server.OpenClient();
IObjectContainer client2 =server.OpenClient();
IList
result1 = client1.Query
(delegate(Article art) { return art.PMID == "7533967" && art.GM_Version == GeneMentionTagger.VERSION; }); IList
result2 = client2.Query
(delegate(Article art) { return art.PMID == "7533967" && art.GM_Version == GeneMentionTagger.VERSION; }); Article a = result1.Next(); // 修改 a 的內容 client1.Store(a); client2.Ext().Refresh(a,Int16.MaxValue); // 取得更新後的內容 client1.Commit();

遠端資料庫伺服器

要讓 db4o 能夠使用 TCP/IP 網路存取遠端的資料庫方法很簡單,只要指定連接埠大於零,並且設定一至多個 client 即可!
IObjectServer server = Db4oFactory.OpenServer("db_filename",
655);
server.GrantAccess("user", "passwd");
try
{
    IObjectContainer client = Db4oFactory.OpenClient("localhost",
    655, "user", "passwd");
    // Do something with this client, or open more clients
    client.Close();
}
finally
{
    server.Close();
}

如上例所示,client 連接提供了主機、埠號、使用者名稱和密碼的設定。

就這樣...其它的使用方式就跟在本地端一模一樣。

db4o 中的 Transparent Persistence

如之前的文章提及,更新深度讓我們可以細緻化的控制物件的更新長度,以便在效能和便利上取得平衡,然而也造成下面的問題:
  • 設定特定更新深度:程式碼必須知道哪些物件對應的更新深度
  • 當更新深度為最大值時,會造成效能低落,沒用到的物件會被無意義的更新
一個解決方法也許是讓 db4o 引擎去幫你作決定。這個功能在 db4o 7.1 版時引入,稱之為「Transparent Persistence」(後文簡稱 TP)。db4o 藉由下面方式來支援 TP:
  1. 資料庫必須組態成 TransparentPersistenceSupport
  2. Persistent 類別必須實做 IActivatable 介面,該介面在 db4o 的 Activation一文中有介紹。該介面提供了 bind 方法取得 container 的 activator 物件。
  3. 當物件的欄位被修改時, db4o 的 Activation一文中提及的 Activate() 方法會被呼叫來儲存物件內容。而 db4o 的 Activation的程式碼中出現的 ActivationPurpose.Write 會在 TP 中被使用。
假設使用在 db4o 的 Activation一文中定義的 Article 物件,我們在開啟資料庫前,先設定好 TP 支援:
Db4oFactory.Configure().Add(new TransparentPersistenceSupport());
只要加上這行,再更新物件內容時,只要該物件欲更新的欄位有加上 ActivationPurpose.Write,則會被自動儲存。

db4o 的 Activation一文中提及的主要是取出物件時的情況,這裡是儲存物件的情況

db4o 的 Activation

我們在之前的文章提過關於物件更新深度的問題。db4o 的 Activation 則是設計用來簡化處理更新深度問題,達到 transpartent activation 的效果!

如同在物件更新深度一文中提到的,我們先將資料庫內塞滿 Article 物件。若是我們不再開啟資料庫前設定好更新深度的相關參數,則可能會造成取出的物件有部分內容是 null 值。

要讓 db4o 運行於 Transparent Activation 模式的方法很簡單:

Db4oFactory.Configure().Add(new TransparentActivationSupport());
就這樣,我們不需要再擔心會遇到 null 值的問題了!實際上,當啟用 Transparent Activation 模式時,任何未實做 Db4objects.Db4o.TA.IActivatable 介面的物件被使用時將會自動的 activate。很明顯的是,這種方式會造成記憶體的大量消耗,也造成載入時間變慢。要避免這種情況,我們可以替我們的類別實做 Activatable 介面。下面是我們將 Article 物件加上 Activatable 的實做:
public class Article: IActivatable
{  
   // ...

   [Transient]
   private IActivator _activator;

   private Sentence title;  
   public Sentence SentenceOfTitle  
   {  
       get { Activate(ActivationPurpose.Read);
             return title; }  
       set { Activate(ActivationPurpose.Write);
             title = value; }  
   }  
   
   // 這裡假設 IsStructure 不需要 activation
   private bool _IsStructure;  
   public bool IsStructure  
   {  
       get { // Activate(ActivationPurpose.Read);
             return _IsStructure; }  
       set { // Activate(ActivationPurpose.Write);
             _IsStructure = value; }  
   }  
   
    private List _SentencesOfAbs;  
    public List SentencesOfAbstract  
    {  
       get { Activate(ActivationPurpose.Read);
             return _SentencesOfAbs; }  
       set { Activate(ActivationPurpose.Write);
             _SentencesOfAbs = value; }  
    }  

    public override String ToString()
    {
       Activate(ActivationPurpose.Read);
       return string.Format("T:{0}", title);
    }

    // implement IActivatable
    public void Activate(ActivationPurpose purpose)
    {
        if(_activator != null)
        {
            _activator.Activate(purpose);
        }
    }
    public void Bind(IActivator activator)
    {
        if (_activator == activator)
        {
            return;
        }
        if (activator != null && null != _activator)
        {
            throw new System.InvalidOperationException();
        }
        _activator = activator;
    }
} 
一個 IActivatable 類別必須儲存 db4o 提供給 bind 方法的Activator 物件於一個 transient 變數中(上例中的 _activator 變數),並且在預被 active 的欄位被呼叫前,呼叫 Activate() 方法。假若該物件已經被 activate,這個方法會立即回傳,否則 activation 會自動發生。

db4o 的 Transaction

在 db4o 中,基本上我們對資料庫做任何動作,都處於一個 transaction 中;也就是說,當我們開啟一個 db4o 的 container,就會自動啟始一個 transaction,當我們關閉 container 時,也會自動的進行 commit。 若是我們要 rollback 回前一次的 commit 點,則可以直接呼叫 Rollback() 方法: 但是,事實上,這邊存在一個問題,那就是:當我們對於一個存資料庫取出的物件做修改後(稱為 live object),那麼我們就無法 rollback 該物件於資料庫中。 我們必須要明確的刷新我們的 live object,方法如下:

2009年4月4日 星期六

用 index 改善 db4o query 的效能

在 code 中記得要對會需要進行 query 的 field 進行 index,可以大幅改善效能。下面是一個例子:
Db4oFactory.Configure().ObjectClass(typeof(GeneOntologyInfo)).ObjectField("id").Indexed(true);  // 重點是這段;因為我們會常常搜尋 id==X 的物件,故對該 field 進行 index
gene2GO = Db4oFactory.OpenFile(GENE2GO_DB);
using (StreamReader r = new StreamReader(GENE2GO_SOURCE))
{
 while ((line = r.ReadLine()) != null)
 {                            
   string[] info = Regex.Split(line, @"\t");
   GeneOntologyInfo ginfo = new GeneOntologyInfo(info[2], info[3], info[4], info[0]);
   gene2GO.Store(ginfo);
 }
}


// query 的程式碼
IQuery query = gene2GO.Query();
query.Constrain(typeof(GeneOntologyInfo));
query.Descend("id").Constrain(id);
IObjectSet result = query.Execute();
// 略

2008年9月12日 星期五

db4o 與結構化的物件;如何處理物件間的關連

我們導入另一個更複雜的物件 Article:

儲存結構化的物件

如同儲存一般物件一樣,我們也是呼叫 Set() 方法來儲存 Article 物件。與 Article 物件關連的 Sentence 物件會被自動儲存!
string pmid = "123";
string title = "sent0";
Article article = new Article(pmid, title);
List abs=new List();
abs.Add(new Sentence("sent1","METHOD"));
abs.Add(new Sentence("sent2","METHOD"));
abs.Add(new Sentence("sent3","CONCLUSION"));
article.SentencesOfAbstract=abs;

db.Set(article);
上面的程式碼相當於我們手動將各物件存入資料庫:
List abs=new List();
abs.Add(new Sentence("sent1","METHOD"));
abs.Add(new Sentence("sent2","METHOD"));
abs.Add(new Sentence("sent3","CONCLUSION"));
db.Set(abs);

string pmid = "123";
string title = "sent0";
Article article = new Article(pmid, title);
article.SentencesOfAbstract=abs;
db.Set(article);

取回結構化物件

QBE

要取回所有的 Article 物件,我們跟以前一樣,只要提供一個空的 prototype 即可:
Article proto = new Article(null,null);
IObjectSet result = db.Get(proto);
ListResult(result);
當然,我也可以取回所有的 Sentence 物件!
Sentence proto = new Sentence(null,null);
IObjectSet result = db.Get(proto);
ListResult(result);
我們也可以取得所有 Article 物件中滿足 section 為 TITLE 的 Sentence 物件:
Sentence title = new Sentence(null,"TITLE");
Article article = new Article(null,title);
IObjectSet result = db.Get(article);
ListResult(result);

Native Queries

對結構化物件使用 Native Query 跟一般物件幾乎一模一樣。下面示範如何取回 一群 Article 物件,使其 Title Sentence 滿足指定的參數:
/// C# .NET 1.1
public class RetrieveArticlesByTitlePredicate : Predicate
{
   readonly string _title;
   public RetrieveArticlesByTitlePredicate(string title)
   {
      _title = title;
   }
   public bool Match(Article candidate)
   {
      return candidate.SentenceOfTitle.RawText == _title;
   }
}

// 使用方法
string title = "sent0";
IObjectSet results = db.Query(new
RetrieveArticlesByTitlePredicate(title));
ListResult(results);

/// C# .NET 2.0
string title = "sent0";
List
results = db.Query
(delegate(Article article) { return article.SentenceOfTitle.RawText == title; }); listResults(results);

SODA Query API

使用 SODA 的話,必須 descend 兩次以便取得 rawText:
IQuery query = db.Query();
query.Constrain(typeof(Article));
query.Descend("title").Descend("rawText")
.Constrain("sent0");
IObjectSet result = query.Execute();
ListResult(result);
另外,我們也可以藉由指定 SentenceOfTitle 欄位來達到相同的效果:
IQuery query = db.Query();
query.Constrain(typeof(Sentence));
Sentence proto = new Sentence("sent0", null);
query.Descend("title").Constrain(proto);
IObjectSet result = query.Execute();
ListResult(result);
下面我們示範如何取得所有 PMID 為 123 的 SentencesOfAbstract 欄位:
IQuery artQuery = db.Query();
artQuery.Constrain(typeof(Article));
artQuery.Descend("pmid").Constrain("123");
IQuery sentQuery = artQuery.Descend("_SentencesOfAbs");
IObjectSet result = sentQuery.Execute();
ListResult(result);

更新結構化物件

如同一般物件一般,要更新結構化物件,也是對它們再次呼叫 Set() 方法:
IObjectSet result = db.Get(new Article("123",null));
Article found = (Article)result.Next();
found.SentenceOfTitle = new Sentence("sentXYZ",null);
db.Set(found);
下面我們嘗試直接更新 SentenceOfAbstract 物件內容:
IObjectSet result = db.Get(new Article("123",null));
Article found = (Article)result.Next();
List abs=new List();
abs.Add(new Sentence("sent1","INTRODUCTION"));
abs.Add(new Sentence("sent2","METHOD"));
abs.Add(new Sentence("sent3","CONCLUSION"));
found.SentenceOfAbstract=abs;
db.Set(found);
看起來似乎一切都很簡單、美好?但是實際上,若是我們再度存取資料庫,檢查我們的更新:
result = db.Get(new Article("123",null));
ListResult(result);
我們會發現,更新並未成功!這是因為效能上的考量,db4o 不會自動的更新結構化物件內的所有成員類別!為了兼顧效能與程式碼撰寫的簡潔,db4o 導入了 update depth 的概念,來控制程式在更新時,物件成員樹的更新深度。

update depth

對於所有的物件而言,預設的 update depth 是 1,代表只有 primitive 以及 String 成員會被更新。

db4o 提供了相當精細的方法來控制 update depth。下面我們藉由設定 CascadeOnUpdate 為 true,指定 db4o 完整的更新 Article 物件的內容:

Db4oFactory.Configure().ObjectClass(typeof(Article))
.CascadeOnUpdate(true);
// 接下來才去設定 Article 物件內容
要注意的地方是,先設定好 update depth 後才去更新才有效。

刪除結構化物件

一樣,用 Delete() 方法即可:
IObjectSet result = db.Get(new Article("123",null));
Article found = (Article)result.Next();
db.Delete(found);
result = db.Get(new Car(null));
我們應該會認為 db4o 應該也會把 Article 物件內一堆的 Sentence 物件也刪除了吧?但是實際上, db4o 並不會幫我們做這件事!

遞迴刪除結構化物件內成員

跟更新時一樣,我們可以設定 db4o,幫我們完成這件事:
Db4oFactory.Configure().ObjectClass(typeof(Article))
.CascadeOnDelete(true);

// 接下來才去刪掉
// ...
另外要注意的一點是,目前的 db4o 版本(6.0)中,就算我們要刪除的資料庫物件,目前仍然被程式內的變數參考到,它們經由遞迴刪除後,一樣會被從資料庫內移除。

2008年9月11日 星期四

db4o 的 query 方法簡述

db4o 提供三種 query 系統。

Query-By-Example;QBE

QBE 使用上相當簡單,只要提供 db4o 一個 template 物件,db4o 會自動回傳符合 template 物件中非預設欄值的所有物件。這是經由 reflecting 機制加以建立一個 query expression,其利用 AND 將所有非預設值欄位加以結合。

這個方式有下列幾點限制:
  • db4o 必須 reflect template 物件的所有成員
  • 我們無法進行更進接的 query expressions(比如 AND、OR、NOT)
  • 我們無法建立某些特殊的限制條件,比如值必須是整數 0、空字串或是 null。因為它們會被解譯為非條件。
這些限制,都可以藉由 Native Query(NQ)系統加以解決。

Native Queries

Native queries 是 db4o 主要的 query 介面。其概念可以參考如下兩篇白皮書:

範例

在 C# 1.1 中,我們必須建立一個繼承自 com.db4o.Predicate 的類別,並且必須實作 Match() 方法,其傳入的參數決定了物件的範圍。
bool Match(Sentence candidate);

下面我們看一個更複雜的 query;我們嘗試找出所有的 Sentence 物件,並滿足:section 必須為 TITLE,並且其 sentence 長度不能大於 20 個字:

// C# .NET 2.0
IList <Sentence> result = db.Query%lt;Sentence> (delegate(Sentence sent) {
return sent.RawText.Length < 20 && sent.SECTION == "TITLE";
});
原則上,我們可以將任意的程式碼轉化為 Native Query,只要我們知道自己在做什麼就好了...我們再看一個例子:

SODA Query API

SODA query API 是 db4o 最底層的 query API,使用它能讓我們直接存取 query graph 上的節點。因為 SODA 使用字串來識別欄位,因此本身缺乏程式語言的支援(比如編譯時期型態檢驗),而且撰寫起來也比較冗長。因此對於大部分的應用而言, Native Query 會是比較好的選擇!然而,因為有一些應用,有動態產生 query 的需求,這時就需要用到 SODA。

範例

下面示範如何利用 SODA 取回全部的 Sentence 物件。我們利用 ObjectContainer 的 Query() 方法建立了 Query 物件,接著我們可以藉由 Constraint 物件加入限制到 Query 物件中:
IQuery query = db.Query();
query.Constrain(typeof(Sentence));
IObjectSet result = query.Execute();
ListResult(result);
要經由 section 名取得某個 Sentence 物件,我們必須利用 Descend() 方法進一步的加強限定它的 Section 欄位:
IQuery query = db.Query();
query.Constrain(typeof(Sentence));
query.Descend("section").Constrain("TITLE");
IObjectSet result = query.Execute();
ListResult(result);
值的一提的是,類別限定其實可以拿掉;假若去掉類別限定,我們將會 query 取得所有包含指定的 section 資料欄位值的物件。再看另一個例子:
IQuery query = db.Query();
query.Constrain(typeof(Sentence));
query.Descend("rawText").Constrain("Pain management: evaluating the effectiveness of an educational programme for surgical nursing staff.");
IObjectSet result = query.Execute();
ListResult(result);

進階範例

有時我們並不確定某特定欄位,但是需要去 query 符合特定範圍值的物件,或是不包含特定值的物件,這些都可以經由 Constraint API 辦到。

下面的例子找出,所有 RawText 不是「Pain management: evaluating the effectiveness of an educational programme for surgical nursing staff.」的 Sentence 物件:
IQuery query = db.Query();
query.Constrain(typeof(Sentence));
query.Descend("rawText").Constrain("Pain management: evaluating the effectiveness of an educational programme for surgical nursing staff.").Not();
IObjectSet result = query.Execute();
ListResult(result);
我們也可以加入其它的邏輯運算:
IQuery query = db.Query();
query.Constrain(typeof(Sentence));
IConstraint constr = query.Descend("rawText")
.Constrain("Pain management: evaluating the effectiveness of an educational programme for surgical nursing staff.");
// 也可以用 .Or(constr);
query.Descend("section")
.Constrain("TITLE").And(constr);

IObjectSet result = query.Execute();
ListResult(result);
我們也利用限制來比較給定的值:
IQuery query = db.Query();
query.Constrain(typeof(Sentence));
// 找到長度大於 50 的 Sentence 物件
query.Descend("length")
.Constrain(50).Greater();
IObjectSet result = query.Execute();
ListResult(result);
SOAD API 也允許我們去 query 欄位值為資料型態的預設值的物件:
Sentence s = new Sentence("Sentence 1", null);
db.Set(s);
IQuery query = db.Query();
query.Constrain(typeof(Sentence));
query.Descend("section").Constrain(null);
IObjectSet result = query.Execute();
ListResult(result);
db.Delete(s);
我們也可以請 db40 對 query 結果進行排序:
IQuery query = db.Query();
query.Constrain(typeof(Sentence));
query.Descend("length").OrderAscending();
IObjectSet result = query.Execute();
ListResult(result);
query.Descend("length").OrderDescending();
result = query.Execute();
ListResult(result);
前述的所有範例都可以任意結合,形成更複雜的 query。最後我們示範如何清除資料庫內所有的 Sentence 物件:
IObjectSet result = db.Get(typeof(Sentence));
foreach (object item in result)
{
  db.Delete(item);
}

2008年8月26日 星期二

db4o 簡介與初探

db4o object database 引擎主要由一單獨的 DLL 組成。目前版本支援了 Microsoft .NET. framework 1.0/1.1 以及 2.0。

一般 .NET framework 的 DLL 檔位於安裝目錄內的 bin/net/ 目錄底下;.NET Compact Framework 則位於 bin/compact/ 下(我使用的 6.4 版本檔名為 Db4objects.Db4o.dll)。在開發時,必須將這個 DLL 加入到參考中。

Db4objects.Db4o namespace

包含了大部分開發所需要用到的功能。其中最重要的兩個類別是 Db4objects.Db4o.Db4oFactory 和 Db4objects.Db4o.IObjectContainer。

  • Db4oFactory:提供的靜態方法讓我們可以開啟資料庫檔案、啟動伺服器或是連線到既存的伺服器。另外,它也允許我們再開啟資料庫前先設定好 db4o 的環境變數。
  • IObjectContainer:則是我們最常會使用到,也是最重要的資料庫程式介面。它代表的就是我們的 db4o 資料庫。
    • IObjectContainer 可能是處於單一使用者模式的某個資料庫,或是一個連線到某個 db4o 伺服器的客戶端連線。
    • 每一個 IObjectContainer 都擁有一個 transaction。每個執行的動作都是處於 transaction 狀態;當我們開啟一個 IObjectContainer,我們就處於一個 transaction 之中;當我們下達 Commit() 或是 Rollback(),將會馬上切換到另一個 transaction。
    • 只要我們有在操作 IObjectContainers,它將會持續保持開啟連接的狀態。當我們關閉一個 IObjectContainer,所有存在記憶體中的資料庫參考將會被丟棄。

第一個 db4o 程式

我們首先常是如何儲存、擷取、更新和刪除某個只包含 primitive 以及字串成員的類別 。

public class Sentence
{
 private string rawText;

 /// raw 參數代表原本的文字內容
 /// section 參數則為該文字所屬的 section
 public Sentence(string raw, string section)
 {
     rawText = raw;
     this.section = section;
 }
 public string RawText
 {
     get { return rawText; }
     set { rawText = value; length=value.Length}
 }
 private int length;
 public int Length
 {
     get { return length; }
     set { length = value; }
 }

 private string html;
 public string HTML
 {
     get { return html; }
     set { html = value; }
 }
 private string section;
 public string Section
 {
     get { return section; }
     set { section = value; }
 }
}

開啟資料庫

要存取一個 db4o database 資料檔或是建立一個新的資料庫,我們只要呼叫 Db4oFactory.OpenFile(),並提供我們想要存取的資料庫檔案路徑當作參數及可。該方法會回傳一個 IObjectContainer 實例。

如前述,IObjectContainer 代表的就是一個資料庫,並且扮演了我們跟 db4o 將的主要溝通橋梁。藉由呼叫 Close() 方法,將關閉該 IObjectContainer 資料庫檔,並且是放所有參考到的資訊。

// accessDb4o
IObjectContainer db = Db4oFactory.OpenFile(dbfilename);
try
{
// do something with db4o
}
finally
{
  db.Close();
}

儲存物件

要儲存某個物件,我們只要對我們的資料庫呼叫 Set() 方法,並且存給它某個物件當作參數及可!

// store First Sentence object
Sentence s = new Sentence("Pain management: evaluating the effectiveness of an educational programme for surgical nursing staff.", "Title");
db.Set(s);
Console.WriteLine("Stored {0}", s);

取回物件

db4o 提供三種不同的 query 系統:

  • Query by Example (QBE)
  • Native Queries (NQ)
  • SODA Query API (SODA)
這裡我們先嘗試利用 QBE。而 NQ 則是 db4o 主要的 query 介面,文件也建議開發者使用該介面為主。

當使用 QBE 時,我們會提供 db4o 一個原型物件(prototypical object)作為我們想要取得的物件的一個範例,並呼叫 Get() 方法。db4o 將會依據傳給 Get() 方法的物件的內容,從資料庫內取得包含跟我們提供的物件一樣資料值欄位的所有物件(非預設值;一般物件的預設值為 null,int 為 0),並以 ObjectSet 實例回傳(代表所有符合的物件)。

下面我們示範如何從資料庫中取得所有的 Sentence 實例。方法很簡單,我們只要提供一個空的 Sentence 原型即可(所有的資料欄位值都為預設值):

Sentence sents = new Sentence(null, null);
ObjectSet result = db.Get(sents);
ListResult(result);

// ...略

public static void ListResult(IObjectSet result)
{
    Console.WriteLine(result.Size());
    while (result.HasNext())
    {
        Console.WriteLine(result.Next());
    }
}

db4o 另外提供了一個簡便的方法讓我們可以取得某類別的所有實例:

ObjectSet result = db.Get(typeof(Sentence));
ListResult(result);
對於泛型物件,可以利用 query() 方法取得:
IList <Sentence> sents = db.query<Sentence>(typeof(Sentence));

下面示範如何依據 section 來查詢:

Sentence sent = new Sentence(null, "BACKGROUND");
ObjectSet result = db.Get(sent);
ListResult(sent);

更新物件

更新物件跟儲存物件的動作很類似;我們也是呼叫同樣的 Set() 方法:

ObjectSet result = db.Get(new Sentence(null, "TITLE"));
Sentence found = (Sentence)result.Next();
found.Section="BACKGROUND";
db.Set(found);
Console.WriteLine("Modified section for" + found);

注意很重要的一點是我們第一個步驟是先去 query 物件。假若,當我們呼叫 Set() 方法去修改一個未知的(但是實際上我們想要修改的是既存的物件)的物件;也就是說我們沒有先去 queyr 物件,那麼 db4o 將會在資料庫內插入一個新的物件。db4o 並不會自動的把我們產生的物件跟資料庫內的物件進行比對;它假設我們實際上要插入一個剛剛好有同樣值的物件到資料庫內。

刪除物件

在資料庫內的物件可經由 DELETE() 方法加以移除。
IObjectSet result = db.Get(new Sentence("Pain management: evaluating the effectiveness of an educational programme for surgical nursing staff.", null));
Sentence found = (Sentence)result.Next();
db.Delete(found);
Console.WriteLine("Deleted {0}", found);