db4o使用全解
db4o使用全解?
db4o是一種純對象數據庫,相對于 傳統的關系數據庫+ORM,db4o具有以下好處:
1)以存對象的方式存取數據(不過你考慮一下完全以對象的方式去考慮數據的存取對傳統的數據庫設計思維來說是多么大的顛覆)
2)無需數據庫服務器,只需要一個數據文件,且dll大小僅為300多k,非常適合作為嵌入式數據庫;
3)提供Query By Sample, Native Query和Simple Object DataBase Access(SODA)三種方式進行數據查詢,操作簡便且功能強大,和sql說byebye。
同時還有一個叫objectmanager的工具,可用于查看數據文件中保存的對象,不過安裝前需要安裝jvm。
db4o數據庫引擎
/db4o-7.4/bin/net-2.0/Db4objects.Db4o.dll
.NET 2.0 framework平臺的db4o引擎。
/db4o-7.4/bin/compact-2.0/Db4objects.Db4o.dll
.NET 2.0 CompactFramework平臺的db4o引擎。
一、首先,Db4objects.Db4o 、Db4objects.Db4o.Query 命名空間是我們所需要關心的。
1.Db4objects.Db4o
Db4objects.Db4o 命名空間包含了幾乎所有通常所需要用到的功能。
其中有兩個值得留意的類:Db4objects.Db4o.Db4oFactory 和Db4objects.Db4o.IObjectContainer。
而Db4oFactory 工廠類是我們進行開發的起始點,該類的靜態方法提供了打開數據庫文件、啟動服務器或者連接到已有的服務器的功能,同時在打開數據庫前,你還可以通過它來配置db4o的環境。
IObjectContainer是一個99%的時間都會用到的、最重要的接口:在開發過程中,它就是你的db4o數據庫。
- IObjectContainer 可以作為單用戶模式的數據庫,也可以作為db4o服務器的客戶端連接。
- 每個IObjectContainer 持有一個事務,所有的操作都是事務相關的。 當你打開一個IObjectContainer時 ,事務已經開始了,當你commit()或者rollback(),它將會馬上啟動下一個事務。
- 每個IObjectContainer 會自己管理那些被其存儲并實例化的對象的引用。而做這些工作的同時,它還管理這對象的唯一標識,這樣是它能夠達到很高的性能。
- 在使用IObjectContainer 的過程中,只要你還在使用它,它就會一直保持打開狀態。而當你關閉這個ObjectContainers時,所有保存在內存中的對象引用都將被丟棄掉。
2.Db4objects.Db4o.Query
Db4objects.Db4o.Query 包中包含了用來構造原生查詢的Predicate類。Native Query接口是db4o最主要的查詢接口,并且它應該比Soda查詢API更常用。
3.Db4objects.Db4o.Ext?
每個IObjectContainer 對象同時也是一個IExtObjectContainer對象。你可以把它轉換成IExtObjectContainer,或者可以使用.Ext() 方法來獲得更高級的特性。
4.Db4objects.Db4o.Config
Db4objects.Db4o.Config 命名空間里面包含了配置db4o所需的類型和類
二、例子
//實體類,注意這個類中沒有包含任何和db4o有關的代碼。
namespace Db4objects.Db4o.Tutorial.F1.Chapter1?
{?
public class Pilot?
{?
? ?string _name;?
? ?int _points;?
? ?public Pilot(string name, int points)?
? ? {?
? ? ?_name = name;?
? ? ?_points = points;?
? ? }?
? ?public string Name {get{return _name;}}
? ?public int Points {get{return _points;}} ? ?
? ?public void AddPoints(int points)
? ? {?
? ? ?_points += points;?
? ? } ? ??
? ?override public string ToString()?
? ? {?
? ? ?return string.Format("{0}/{1}", _name, _points);?
? ? }?
}?
}?
1.打開、關閉數據庫(YAP文件)
IObjectContainer db = Db4oFactory.OpenFile("data.yap"); //打開本地數據庫data.yap,如果該文件不在,則自動創建數據庫文件。
try{// do something with db4o}?
finally{
db.Close(); //關閉}?
/*要訪問或新建一個db4o數據庫文件,把文件存儲路徑作為參數調用Db4oFactory.OpenFile()方法獲取一個 IObjectContainer 實例。IObjectContainer 就代表"數據庫",它將是你操作db4o的主要接口。調用#close()方法來關閉IObjectContainer ,這樣做也將關閉數據庫文件并且釋放所有關聯的資源。*/
2.保存對象
//要保存對象,只需在數據庫上調用Store()方法,以任意對象為參數傳入即可。
Pilot pilot1 = new Pilot("Michael Schumacher", 100);?
db.Store(pilot1);
//再來存一個
Pilot pilot2 = new Pilot("Rubens Barrichello", 99);?
db.Store(pilot2);?
3.查詢對象
Db4o提供三種不同的查詢機制,樣本查詢(QBE),原生查詢(NQ)和SODA查詢接口(SODA)。推薦使用NQ
- 原生查詢的目標是成為db4o的首要接口,因此它應該作為首選。
- 鑒于當前原生查詢優化器的狀態,某些查詢使用SODA風格能夠獲得更快的執行速度,因此它被用于對應用進行優化。SODA對于在運行時構造動態查詢也是非常方便的。
- 樣本查詢是非常簡單的單行查詢,但在功能上存在局限。如果你喜歡這種方式,并且它能夠滿足你的應用要求的話,仍可以使用。
3.1使用QBE查詢
在使用QBE時,你要創建一個原型對象作為你要讀取對象的樣本。db4o會讀取所有指定類型的對象,這些對像含有與樣本一樣(并非缺省)的屬性值。結果以 IObjectSet 實例的形式返回。
也就是說,在使用QBE時,你需要提供給db4o一個模板對象。db4o將返回所有匹配此模板的無默認字段值(non-default field values)。這些工作是通過反射所有字段、創建查詢表達式來完成的,在查詢表達式中所有的無默認值字段都被AND表達式連接在一起。
使用QBE方式查詢存在著一些明顯的局限性:
- db4o必須反射所有樣本對象的成員。
- 你不能執行高級的查詢表達式。(AND,OR,NOT等)
- 你不能針對象0(整數)這樣的字段值、""(空白字符串)或者null(引用類型)進行約束限制。因為它們都將被解釋為不受約束限制的。
- 你必需能夠使用無初始化字段的方式來創建對象,這意味著你不能在字段聲明時對其進行初始化。最難的是,你不能強行約定某個類的對象只能處于這種定義良好的初始化狀態。
- 你需要一個沒有任何初始化字段的構造函數來創建對象。
我們這里寫一個ListResult()方法,用來顯示查詢結果對象集中的內容。
public static void ListResult(IObjectSet result)?
{?
Console.WriteLine(result.Count);?
foreach (object item in result)?
{Console.WriteLine(item);}?
}
要從數據庫獲取所有賽車手,我們可以給一個空的原型:
//retrieveAllPilotQBE?
Pilot proto = new Pilot(null, 0);?
IObjectSet result = db.QueryByExample(proto);?
ListResult(result);
//注意我們設定分數為0,但是我們的查詢結果并沒有受此約束,因為0是int類型的缺省值。
db4o還提供一個快捷方式來獲取一個類的所有實例:
//retrieveAllPilots?
IObjectSet result = db.QueryByExample(typeof(Pilot));?
ListResult(result);
.NET 2.0也有一個泛型快捷方式,這樣使用query方法:
IList <Pilot> pilots = db.Query<Pilot>(typeof(Pilot));
使用名字查詢賽車手,代碼如下:
// retrievePilotByName?
Pilot proto = new Pilot("Michael Schumacher", 0);?
IObjectSet result = db.QueryByExample(proto);?
ListResult(result);
使用給定的分數查詢賽車手,代碼如下:
// retrievePilotByExactPoints?
Pilot proto = new Pilot(null, 100);?
IObjectSet result = db.QueryByExample(proto);?
ListResult(result);
3.2使用NQ查詢
原生查詢NQ是db4o的主要查詢接口,它是查詢數據庫的推薦方式。由于原生查詢簡單地使用了編程語言的語法,因此它是非常標準化的,并且是一種面向未來的安全選擇。
原生查詢具備根據某個類的所有實例來運行一行或是多行代碼的能力。原生查詢表達式返回true來表示結果集中存在著某些特定實例。db4o將嘗試優化原生查詢表達式,并依靠索引運行表達式,而無需實例化實際的對象。?
缺點:在內部,db4o嘗試分析原生查詢并將其轉換為SODA。
//C# .NET 2.0
IList <Pilot> pilots = db.Query <Pilot> (delegate(Pilot pilot){return pilot.Points == 100;});
//C# .NET 1.1
IList pilots = db.Query(new PilotHundredPoints());
public class PilotHundredPoints : Predicate {
public boolean Match(Pilot pilot)?
{return pilot.Points == 100;}
}
請注意在上面的語法中:對于所有不支持類屬的方言,NQ遵守約定工作。某個擴展自com.db4o.Predicate的類需要有一個boolean Match()方法,此方法接受一個描述類范圍的參數:bool Match(Pilot candidate);
*在使用NQ時,不要忘記如果你使用模板和自動完成技術的話,可用現代化集成開發環境(IDEs)來幫你完成所有原生表達式相關的代碼錄入工作。?
下面的示例展示了如何同一個查詢在不同語言中使用原生查詢語法的相似性,它們完全可以使用自動完成功能、重構和其他IDE特性,并在編譯時作檢查:
//C# .NET 2.0
IList <Pilot> result = db.Query<Pilot> (delegate(Pilot pilot) {
return pilot.Points > 99
? ? ? ? && pilot.Points < 199
? ? ? ? || pilot.Name == "Rubens Barrichello";});
基本上,這就是NQ之所以能夠被高效使用的原因。原則上,你可以將任意代碼作為NQ來運行,但你需要非常小心某些方面的影響-尤其是那些可能對持久化對象發生作用的影響。
讓我們運行一個示例來調用更多可用的語言特性:
using Db4objects.Db4o.Query;
namespace Db4objects.Db4o.Tutorial.F1.Chapter1
{
public class ArbitraryQuery : Predicate
{
? ?private int[] _points;
? ?public ArbitraryQuery(int[] points)
? ? {
? ? ?_points=points;
? ? }
? ?public bool Match(Pilot pilot)
? ? {
? ? ?foreach (int points in _points)
? ? ? {
? ? ? ?if (pilot.Points == points)
? ? ? ? {return true;}
? ? ? }
? ? ?return pilot.Name.StartsWith("Rubens");
? ? }
}
}?
3.3使用SODA查詢
SODA查詢API是db4o的低級查詢API,它允許直接訪問查詢圖表(query graphs)的節點。由于SODA使用字符串標識字段,因此它并不是非常類型安全的,也不是編譯時可檢查的,并且編寫的代碼冗長。
對于大多數應用來講,原生查詢將是更好的查詢接口。?
以前面QBE查詢轉換為SODA為例,一個新的Query對象通過ObjectContainer的query()方法創建,我們可用在其上添加Constraint類實例。為了找到所有的Pilot實例,我們對Pilot類對象的查詢進行了約束限制。
// retrieveAllPilots
IQuery query = db.Query();
query.Constrain(typeof(Pilot));
IObjectSet result = query.Execute();
ListResult(result);
我們正在將"真正的"原型(prototype)交換為我們希望捕捉到的對象元描述(meta description):一個查詢圖表由多個查詢節點和約束構成。每個查詢節點都是一個存放候選對象的地方,每個約束則標識了是否從結果集中添加還是排除候選者。
而我們使用”descend”的目的是將 附加的約束條件增加到表達式樹中以判斷我們的候選對象,即添加約束
// retrievePilotByName?
//滿足這個查詢的候選對象需要是Pilot類型并且其數據成員”name”必須與給出的字符串相匹配才能加入到結果集中。
IQuery query = db.Query();
query.Constrain(typeof(Pilot));
query.Descend("_name").Constrain("Michael Schumacher"); //添加_name為Michael Schumacher的約束?
IObjectSet result = query.Execute();
ListResult(result);
// retrievePilotByExactPoints
IQuery query = db.Query();
query.Constrain(typeof(Pilot));
query.Descend("_points").Constrain(100); //添加_points為100的約束
IObjectSet result = query.Execute();
ListResult(result);
SODA另外高級查詢
query.Descend("_name").Constrain("Michael Schumacher").Not();?
//_name不是Michael Schumacher的pilot的約束
query.Descend("_name").OrderAscending(); //排序asc 升序
query.Descend("_name").OrderDescending(); //排序desc 降序
IConstraint constr = query.Descend("_name").Constrain("Michael Schumacher");
query.Descend("_points").Constrain(99).And(constr);?
//AND 與
IConstraint constr = query.Descend("_name").Constrain("Michael Schumacher");
query.Descend("_points").Constrain(99).Or(constr);
//OR 或
query.Descend("_points").Constrain(99).Greater(); //大于99 ? 即 >99
query.Descend("_points").Constrain(99).Smaller(); //小于99 ? 即 <99
query.Descend("_points").Constrain(10).Greater().equal(); //大于等于10 ? ?即 >=10
query.Descend("_points").Constrain(10).Smaller().equal(); //小于等于10 ? ?即 <=10
query.Descend("_name").Constrain("est").like(); //模糊查詢,_name里包含"est"的約束
4.更新對象
更新對象和存儲對象一樣容易,實際上,你使用相同的Store()方法去更新你的對象,在你修改任何對象后只需要再次調用Store()就可以了。
注意我們先查詢得到要更新的對象,這點和重要。當你調用Store()去修改一個存儲對象時,如果這個對象不是持久化對象(在前面已經存儲過或者在當前會話中讀取到的對象),db4o將會插入一個新對象。db4o這么做是因為它不會自動比較要存儲的對象和先前存儲過的對象。它認為你是想再存儲一個屬性值一樣的對象。
// updatePilot?
IObjectSet result = db.QueryByExample(new Pilot("Michael Schumacher", 0));?
Pilot found = (Pilot)result.Next();?
found.AddPoints(11);?
db.Store(found);?
Console.WriteLine("Added 11 points for {0}", found);?
RetrieveAllPilots(db);
5.刪除對象
使用Delete()方法,數據將被從數據庫中刪除。
和更新對象一樣,要刪除的對象也必須是持久對象,只是提供一個屬性值一樣的對象是不可以成功刪除的。?
// deleteFirstPilotByName?
IObjectSet result = db.QueryByExample(new Pilot("Michael Schumacher", 0));?
Pilot found = (Pilot)result.Next();?
db.Delete(found);?
Console.WriteLine("Deleted {0}", found);?
RetrieveAllPilots(db);
//我們再來刪除另一個對象,
// deleteSecondPilotByName?
IObjectSet result = db.QueryByExample(new Pilot("Rubens Barrichello", 0));?
Pilot found = (Pilot)result.Next();?
db.Delete(found);?
Console.WriteLine("Deleted {0}", found);?
RetrieveAllPilots(db);
====================================================
目前db4o處理普通struct及enum還不盡如意。
對于普通的struct及enum,db4o不能辨別待儲存/更新的實例與數據庫中原有實例是否同一實例,因此當update時,即使值沒有變動,db4o也會將它new一個出來,儲存入數據庫。如果僅僅只是這樣,不過浪費了一些無謂的IO操作,更大的問題是它儲存進去一個新值,卻不刪除原有的值,導致數據庫文件中存在大量的垃圾數據。
.net下,Int32也是一種struct,然而,從上例日志中卻未發現新建Int32 Code,我猜測是db4o對Int32這些常用struct進行了特殊處理。
為了避免垃圾數據,使用db4o時最好慎用struct。
==========================================================
*對類進行重構,如果只是添加屬性,貌似不需要修改,提取時自動的設為null
Db4o官方網站 http://www.db4o.com/
JackyXu 的博客有數篇關于db4o的筆記 http://www.cnblogs.com/JackyXu/archive/2006/11.html
db4o 中的數據庫重構 http://www.ibm.com/developerworks/cn/java/j-db4o3.html
db4o tutorial翻譯文 http://www.cnblogs.com/dotdty/category/156928.html
敏捷開發利刃(簡介) http://www.cnblogs.com/xiaotie/archive/2008/10/17/1313218.html?
db4o是一種純對象數據庫,相對于 傳統的關系數據庫+ORM,db4o具有以下好處:
1)以存對象的方式存取數據(不過你考慮一下完全以對象的方式去考慮數據的存取對傳統的數據庫設計思維來說是多么大的顛覆)
2)無需數據庫服務器,只需要一個數據文件,且dll大小僅為300多k,非常適合作為嵌入式數據庫;
3)提供Query By Sample, Native Query和Simple Object DataBase Access(SODA)三種方式進行數據查詢,操作簡便且功能強大,和sql說byebye。
同時還有一個叫objectmanager的工具,可用于查看數據文件中保存的對象,不過安裝前需要安裝jvm。
db4o數據庫引擎
/db4o-7.4/bin/net-2.0/Db4objects.Db4o.dll
.NET 2.0 framework平臺的db4o引擎。
/db4o-7.4/bin/compact-2.0/Db4objects.Db4o.dll
.NET 2.0 CompactFramework平臺的db4o引擎。
一、首先,Db4objects.Db4o 、Db4objects.Db4o.Query 命名空間是我們所需要關心的。
1.Db4objects.Db4o
Db4objects.Db4o 命名空間包含了幾乎所有通常所需要用到的功能。
其中有兩個值得留意的類:Db4objects.Db4o.Db4oFactory 和Db4objects.Db4o.IObjectContainer。
而Db4oFactory 工廠類是我們進行開發的起始點,該類的靜態方法提供了打開數據庫文件、啟動服務器或者連接到已有的服務器的功能,同時在打開數據庫前,你還可以通過它來配置db4o的環境。
IObjectContainer是一個99%的時間都會用到的、最重要的接口:在開發過程中,它就是你的db4o數據庫。
- IObjectContainer 可以作為單用戶模式的數據庫,也可以作為db4o服務器的客戶端連接。
- 每個IObjectContainer 持有一個事務,所有的操作都是事務相關的。 當你打開一個IObjectContainer時 ,事務已經開始了,當你commit()或者rollback(),它將會馬上啟動下一個事務。
- 每個IObjectContainer 會自己管理那些被其存儲并實例化的對象的引用。而做這些工作的同時,它還管理這對象的唯一標識,這樣是它能夠達到很高的性能。
- 在使用IObjectContainer 的過程中,只要你還在使用它,它就會一直保持打開狀態。而當你關閉這個ObjectContainers時,所有保存在內存中的對象引用都將被丟棄掉。
2.Db4objects.Db4o.Query
Db4objects.Db4o.Query 包中包含了用來構造原生查詢的Predicate類。Native Query接口是db4o最主要的查詢接口,并且它應該比Soda查詢API更常用。
3.Db4objects.Db4o.Ext?
每個IObjectContainer 對象同時也是一個IExtObjectContainer對象。你可以把它轉換成IExtObjectContainer,或者可以使用.Ext() 方法來獲得更高級的特性。
4.Db4objects.Db4o.Config
Db4objects.Db4o.Config 命名空間里面包含了配置db4o所需的類型和類
二、例子
//實體類,注意這個類中沒有包含任何和db4o有關的代碼。
namespace Db4objects.Db4o.Tutorial.F1.Chapter1?
{?
public class Pilot?
{?
? ?string _name;?
? ?int _points;?
? ?public Pilot(string name, int points)?
? ? {?
? ? ?_name = name;?
? ? ?_points = points;?
? ? }?
? ?public string Name {get{return _name;}}
? ?public int Points {get{return _points;}} ? ?
? ?public void AddPoints(int points)
? ? {?
? ? ?_points += points;?
? ? } ? ??
? ?override public string ToString()?
? ? {?
? ? ?return string.Format("{0}/{1}", _name, _points);?
? ? }?
}?
}?
1.打開、關閉數據庫(YAP文件)
IObjectContainer db = Db4oFactory.OpenFile("data.yap"); //打開本地數據庫data.yap,如果該文件不在,則自動創建數據庫文件。
try{// do something with db4o}?
finally{
db.Close(); //關閉}?
/*要訪問或新建一個db4o數據庫文件,把文件存儲路徑作為參數調用Db4oFactory.OpenFile()方法獲取一個 IObjectContainer 實例。IObjectContainer 就代表"數據庫",它將是你操作db4o的主要接口。調用#close()方法來關閉IObjectContainer ,這樣做也將關閉數據庫文件并且釋放所有關聯的資源。*/
2.保存對象
//要保存對象,只需在數據庫上調用Store()方法,以任意對象為參數傳入即可。
Pilot pilot1 = new Pilot("Michael Schumacher", 100);?
db.Store(pilot1);
//再來存一個
Pilot pilot2 = new Pilot("Rubens Barrichello", 99);?
db.Store(pilot2);?
3.查詢對象
Db4o提供三種不同的查詢機制,樣本查詢(QBE),原生查詢(NQ)和SODA查詢接口(SODA)。推薦使用NQ
- 原生查詢的目標是成為db4o的首要接口,因此它應該作為首選。
- 鑒于當前原生查詢優化器的狀態,某些查詢使用SODA風格能夠獲得更快的執行速度,因此它被用于對應用進行優化。SODA對于在運行時構造動態查詢也是非常方便的。
- 樣本查詢是非常簡單的單行查詢,但在功能上存在局限。如果你喜歡這種方式,并且它能夠滿足你的應用要求的話,仍可以使用。
3.1使用QBE查詢
在使用QBE時,你要創建一個原型對象作為你要讀取對象的樣本。db4o會讀取所有指定類型的對象,這些對像含有與樣本一樣(并非缺省)的屬性值。結果以 IObjectSet 實例的形式返回。
也就是說,在使用QBE時,你需要提供給db4o一個模板對象。db4o將返回所有匹配此模板的無默認字段值(non-default field values)。這些工作是通過反射所有字段、創建查詢表達式來完成的,在查詢表達式中所有的無默認值字段都被AND表達式連接在一起。
使用QBE方式查詢存在著一些明顯的局限性:
- db4o必須反射所有樣本對象的成員。
- 你不能執行高級的查詢表達式。(AND,OR,NOT等)
- 你不能針對象0(整數)這樣的字段值、""(空白字符串)或者null(引用類型)進行約束限制。因為它們都將被解釋為不受約束限制的。
- 你必需能夠使用無初始化字段的方式來創建對象,這意味著你不能在字段聲明時對其進行初始化。最難的是,你不能強行約定某個類的對象只能處于這種定義良好的初始化狀態。
- 你需要一個沒有任何初始化字段的構造函數來創建對象。
我們這里寫一個ListResult()方法,用來顯示查詢結果對象集中的內容。
public static void ListResult(IObjectSet result)?
{?
Console.WriteLine(result.Count);?
foreach (object item in result)?
{Console.WriteLine(item);}?
}
要從數據庫獲取所有賽車手,我們可以給一個空的原型:
//retrieveAllPilotQBE?
Pilot proto = new Pilot(null, 0);?
IObjectSet result = db.QueryByExample(proto);?
ListResult(result);
//注意我們設定分數為0,但是我們的查詢結果并沒有受此約束,因為0是int類型的缺省值。
db4o還提供一個快捷方式來獲取一個類的所有實例:
//retrieveAllPilots?
IObjectSet result = db.QueryByExample(typeof(Pilot));?
ListResult(result);
.NET 2.0也有一個泛型快捷方式,這樣使用query方法:
IList <Pilot> pilots = db.Query<Pilot>(typeof(Pilot));
使用名字查詢賽車手,代碼如下:
// retrievePilotByName?
Pilot proto = new Pilot("Michael Schumacher", 0);?
IObjectSet result = db.QueryByExample(proto);?
ListResult(result);
使用給定的分數查詢賽車手,代碼如下:
// retrievePilotByExactPoints?
Pilot proto = new Pilot(null, 100);?
IObjectSet result = db.QueryByExample(proto);?
ListResult(result);
3.2使用NQ查詢
原生查詢NQ是db4o的主要查詢接口,它是查詢數據庫的推薦方式。由于原生查詢簡單地使用了編程語言的語法,因此它是非常標準化的,并且是一種面向未來的安全選擇。
原生查詢具備根據某個類的所有實例來運行一行或是多行代碼的能力。原生查詢表達式返回true來表示結果集中存在著某些特定實例。db4o將嘗試優化原生查詢表達式,并依靠索引運行表達式,而無需實例化實際的對象。?
缺點:在內部,db4o嘗試分析原生查詢并將其轉換為SODA。
//C# .NET 2.0
IList <Pilot> pilots = db.Query <Pilot> (delegate(Pilot pilot){return pilot.Points == 100;});
//C# .NET 1.1
IList pilots = db.Query(new PilotHundredPoints());
public class PilotHundredPoints : Predicate {
public boolean Match(Pilot pilot)?
{return pilot.Points == 100;}
}
請注意在上面的語法中:對于所有不支持類屬的方言,NQ遵守約定工作。某個擴展自com.db4o.Predicate的類需要有一個boolean Match()方法,此方法接受一個描述類范圍的參數:bool Match(Pilot candidate);
*在使用NQ時,不要忘記如果你使用模板和自動完成技術的話,可用現代化集成開發環境(IDEs)來幫你完成所有原生表達式相關的代碼錄入工作。?
下面的示例展示了如何同一個查詢在不同語言中使用原生查詢語法的相似性,它們完全可以使用自動完成功能、重構和其他IDE特性,并在編譯時作檢查:
//C# .NET 2.0
IList <Pilot> result = db.Query<Pilot> (delegate(Pilot pilot) {
return pilot.Points > 99
? ? ? ? && pilot.Points < 199
? ? ? ? || pilot.Name == "Rubens Barrichello";});
基本上,這就是NQ之所以能夠被高效使用的原因。原則上,你可以將任意代碼作為NQ來運行,但你需要非常小心某些方面的影響-尤其是那些可能對持久化對象發生作用的影響。
讓我們運行一個示例來調用更多可用的語言特性:
using Db4objects.Db4o.Query;
namespace Db4objects.Db4o.Tutorial.F1.Chapter1
{
public class ArbitraryQuery : Predicate
{
? ?private int[] _points;
? ?public ArbitraryQuery(int[] points)
? ? {
? ? ?_points=points;
? ? }
? ?public bool Match(Pilot pilot)
? ? {
? ? ?foreach (int points in _points)
? ? ? {
? ? ? ?if (pilot.Points == points)
? ? ? ? {return true;}
? ? ? }
? ? ?return pilot.Name.StartsWith("Rubens");
? ? }
}
}?
3.3使用SODA查詢
SODA查詢API是db4o的低級查詢API,它允許直接訪問查詢圖表(query graphs)的節點。由于SODA使用字符串標識字段,因此它并不是非常類型安全的,也不是編譯時可檢查的,并且編寫的代碼冗長。
對于大多數應用來講,原生查詢將是更好的查詢接口。?
以前面QBE查詢轉換為SODA為例,一個新的Query對象通過ObjectContainer的query()方法創建,我們可用在其上添加Constraint類實例。為了找到所有的Pilot實例,我們對Pilot類對象的查詢進行了約束限制。
// retrieveAllPilots
IQuery query = db.Query();
query.Constrain(typeof(Pilot));
IObjectSet result = query.Execute();
ListResult(result);
我們正在將"真正的"原型(prototype)交換為我們希望捕捉到的對象元描述(meta description):一個查詢圖表由多個查詢節點和約束構成。每個查詢節點都是一個存放候選對象的地方,每個約束則標識了是否從結果集中添加還是排除候選者。
而我們使用”descend”的目的是將 附加的約束條件增加到表達式樹中以判斷我們的候選對象,即添加約束
// retrievePilotByName?
//滿足這個查詢的候選對象需要是Pilot類型并且其數據成員”name”必須與給出的字符串相匹配才能加入到結果集中。
IQuery query = db.Query();
query.Constrain(typeof(Pilot));
query.Descend("_name").Constrain("Michael Schumacher"); //添加_name為Michael Schumacher的約束?
IObjectSet result = query.Execute();
ListResult(result);
// retrievePilotByExactPoints
IQuery query = db.Query();
query.Constrain(typeof(Pilot));
query.Descend("_points").Constrain(100); //添加_points為100的約束
IObjectSet result = query.Execute();
ListResult(result);
SODA另外高級查詢
query.Descend("_name").Constrain("Michael Schumacher").Not();?
//_name不是Michael Schumacher的pilot的約束
query.Descend("_name").OrderAscending(); //排序asc 升序
query.Descend("_name").OrderDescending(); //排序desc 降序
IConstraint constr = query.Descend("_name").Constrain("Michael Schumacher");
query.Descend("_points").Constrain(99).And(constr);?
//AND 與
IConstraint constr = query.Descend("_name").Constrain("Michael Schumacher");
query.Descend("_points").Constrain(99).Or(constr);
//OR 或
query.Descend("_points").Constrain(99).Greater(); //大于99 ? 即 >99
query.Descend("_points").Constrain(99).Smaller(); //小于99 ? 即 <99
query.Descend("_points").Constrain(10).Greater().equal(); //大于等于10 ? ?即 >=10
query.Descend("_points").Constrain(10).Smaller().equal(); //小于等于10 ? ?即 <=10
query.Descend("_name").Constrain("est").like(); //模糊查詢,_name里包含"est"的約束
4.更新對象
更新對象和存儲對象一樣容易,實際上,你使用相同的Store()方法去更新你的對象,在你修改任何對象后只需要再次調用Store()就可以了。
注意我們先查詢得到要更新的對象,這點和重要。當你調用Store()去修改一個存儲對象時,如果這個對象不是持久化對象(在前面已經存儲過或者在當前會話中讀取到的對象),db4o將會插入一個新對象。db4o這么做是因為它不會自動比較要存儲的對象和先前存儲過的對象。它認為你是想再存儲一個屬性值一樣的對象。
// updatePilot?
IObjectSet result = db.QueryByExample(new Pilot("Michael Schumacher", 0));?
Pilot found = (Pilot)result.Next();?
found.AddPoints(11);?
db.Store(found);?
Console.WriteLine("Added 11 points for {0}", found);?
RetrieveAllPilots(db);
5.刪除對象
使用Delete()方法,數據將被從數據庫中刪除。
和更新對象一樣,要刪除的對象也必須是持久對象,只是提供一個屬性值一樣的對象是不可以成功刪除的。?
// deleteFirstPilotByName?
IObjectSet result = db.QueryByExample(new Pilot("Michael Schumacher", 0));?
Pilot found = (Pilot)result.Next();?
db.Delete(found);?
Console.WriteLine("Deleted {0}", found);?
RetrieveAllPilots(db);
//我們再來刪除另一個對象,
// deleteSecondPilotByName?
IObjectSet result = db.QueryByExample(new Pilot("Rubens Barrichello", 0));?
Pilot found = (Pilot)result.Next();?
db.Delete(found);?
Console.WriteLine("Deleted {0}", found);?
RetrieveAllPilots(db);
====================================================
目前db4o處理普通struct及enum還不盡如意。
對于普通的struct及enum,db4o不能辨別待儲存/更新的實例與數據庫中原有實例是否同一實例,因此當update時,即使值沒有變動,db4o也會將它new一個出來,儲存入數據庫。如果僅僅只是這樣,不過浪費了一些無謂的IO操作,更大的問題是它儲存進去一個新值,卻不刪除原有的值,導致數據庫文件中存在大量的垃圾數據。
.net下,Int32也是一種struct,然而,從上例日志中卻未發現新建Int32 Code,我猜測是db4o對Int32這些常用struct進行了特殊處理。
為了避免垃圾數據,使用db4o時最好慎用struct。
==========================================================
*對類進行重構,如果只是添加屬性,貌似不需要修改,提取時自動的設為null
Db4o官方網站 http://www.db4o.com/
JackyXu 的博客有數篇關于db4o的筆記 http://www.cnblogs.com/JackyXu/archive/2006/11.html
db4o 中的數據庫重構 http://www.ibm.com/developerworks/cn/java/j-db4o3.html
db4o tutorial翻譯文 http://www.cnblogs.com/dotdty/category/156928.html
敏捷開發利刃(簡介) http://www.cnblogs.com/xiaotie/archive/2008/10/17/1313218.html?
總結