Query-By-Example;QBE
QBE 使用上相當簡單,只要提供 db4o 一個 template 物件,db4o 會自動回傳符合 template 物件中非預設欄值的所有物件。這是經由 reflecting 機制加以建立一個 query expression,其利用 AND 將所有非預設值欄位加以結合。
這個方式有下列幾點限制:- db4o 必須 reflect template 物件的所有成員
- 我們無法進行更進接的 query expressions(比如 AND、OR、NOT)
- 我們無法建立某些特殊的限制條件,比如值必須是整數 0、空字串或是 null。因為它們會被解譯為非條件。
Native Queries
Native queries 是 db4o 主要的 query 介面。其概念可以參考如下兩篇白皮書:- Cook/Rosenberger, Native Queries for Persistent Objects, A Design White Paper
- Cook/Rai, Safe Query Objects: Statically Typed Objects as Remotely Executable Queries
範例
在 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); }
沒有留言:
張貼留言