Built-in db4o Blob type helps you to get rid of the problems of byte[] array, though it has its own drawbacks. Pros and Cons for the points, mentioned above:
+ main database file stays a lot smaller
+ backups are possible over individual files
+ the BLOBs are accessible without db4o
- multiple files need to be managed
+ asynchronous storage allows the main application thread to continue its work, while blobs are being stored
- it is more difficult to move objects between db4o database files
+ big objects won't be loaded into memory as part of the activation process
Let's look, how it works.
First, BLOB storage should be defined:
c#: Db4o.Configure().SetBlobPath(storageFolder);
VB: Db4o.Configure().SetBlobPath(storageFolder);
where storageFolder is a String value representing local or server path to store BLOBs. If that value is not defined, db4o will use the default folder "blobs" in user directory.
We will use a modified Car class, which holds reference to the car photo:
01/* Copyright (C) 2004 - 2006 db4objects Inc. http://www.db4o.com */ 02
03
using System; 04
05
namespace Db4objects.Db4odoc.Blobs 06
{ 07
public class Car 08
{ 09
string _model; 10
CarImage _img; 11
12
public Car(string model) 13
{ 14
_model = model; 15
_img=new CarImage(); 16
_img.FileName = _model+".jpg"; 17
} 18
19
public CarImage CarImage 20
{ 21
get 22
{ 23
return _img; 24
} 25
} 26
27
override public string ToString() 28
{ 29
return string.Format("{0}({1})", _model, _img.FileName); 30
} 31
} 32
}
01' Copyright (C) 2004 - 2006 db4objects Inc. http://www.db4o.com 02
03
Imports System 04
05
Namespace Db4objects.Db4odoc.Blobs 06
Public Class Car 07
Dim _model As String 08
Dim _img As CarImage 09
10
Public Sub New(ByVal model As String) 11
_model = model 12
_img = New CarImage() 13
_img.FileName = _model + ".jpg" 14
End Sub 15
16
Public ReadOnly Property CarImage() As CarImage 17
Get 18
Return _img 19
End Get 20
End Property 21
22
Public Overrides Function ToString() As String 23
Return String.Format("{0}({1})", _model, _img.FileName) 24
End Function 25
End Class 26
End Namespace
CarImage is a wrapper to BLOB, representing the photo:
01/* Copyright (C) 2004 - 2006 db4objects Inc. http://www.db4o.com */ 02
03
namespace Db4objects.Db4odoc.Blobs 04
{ 05
06
using Db4objects.Db4o.Ext; 07
using Db4objects.Db4o.Types; 08
using Sharpen.Lang; 09
using Sharpen.IO; 10
11
public class CarImage { 12
IBlob _blob = null; 13
private string _file = null; 14
private string inFolder = "blobs\\in\\"; 15
private string outFolder = "blobs\\out\\"; 16
17
public CarImage() { 18
19
} 20
21
public string FileName 22
{ 23
get 24
{ 25
return _file; 26
} 27
28
set 29
{ 30
_file = value; 31
} 32
} 33
34
public bool ReadFile() 35
{ 36
_blob.ReadFrom(new File(inFolder + _file)); 37
double status = _blob.GetStatus(); 38
while(status > Status.COMPLETED){ 39
Thread.Sleep(50); 40
status = _blob.GetStatus(); 41
} 42
return (status == Status.COMPLETED); 43
} 44
45
public bool WriteFile() 46
{ 47
_blob.WriteTo(new File(outFolder + _file)); 48
double status = _blob.GetStatus(); 49
while(status > Status.COMPLETED){ 50
Thread.Sleep(50); 51
status = _blob.GetStatus(); 52
} 53
return (status == Status.COMPLETED); 54
} 55
} 56
}
01' Copyright (C) 2004 - 2006 db4objects Inc. http://www.db4o.com 02
Imports System.Threading 03
Imports Sharpen.IO 04
Imports Db4objects.Db4o.Ext 05
Imports Db4objects.Db4o.Types 06
07
08
Namespace Db4objects.Db4odoc.Blobs 09
10
Public Class CarImage 11
Dim _blob As IBlob 12
Private _file As String = Nothing 13
Private inFolder As String = "blobs\in\" 14
Private outFolder As String = "blobs\out\" 15
16
Public Sub New() 17
18
End Sub 19
20
Public Property FileName() As String 21
Get 22
Return _file 23
End Get 24
Set(ByVal Value As String) 25
_file = Value 26
End Set 27
End Property 28
29
Public Function ReadFile() As Boolean 30
_blob.ReadFrom(New File(inFolder + _file)) 31
Dim s As Double = _blob.GetStatus() 32
While s > Status.COMPLETED 33
Thread.Sleep(50) 34
s = _blob.GetStatus() 35
End While 36
Return (s = Status.COMPLETED) 37
End Function 38
39
Public Function WriteFile() As Boolean 40
_blob.WriteTo(New File(outFolder + _file)) 41
Dim s As Double = _blob.GetStatus() 42
While s > Status.COMPLETED 43
Thread.Sleep(50) 44
s = _blob.GetStatus() 45
End While 46
Return (s = Status.COMPLETED) 47
End Function 48
End Class 49
End Namespace
inFolder ( "blobs\in\") is used as a location of existing files, which are to be stored into db4o, and outFolder ( "blobs\out\") will be the place for images, retrieved from the database.
readFile method allows blob to be read from the specified location into db4o storage:
c#: IBlob.ReadFrom( File )
IBlob.ReadFrom( File )
As reading is done in a dedicated thread, you can use Blob#getStatus() in a loop to create a progress window.
The same applies to the write operation, which copies BLOB, stored with db4o, to the specified filesystem location.
Let's store some cars together with their images in our database:
01public static void StoreCars() 02
{ 03
File.Delete(YapFileName); 04
IObjectContainer db = Db4oFactory.OpenFile(YapFileName); 05
try 06
{ 07
Car car1=new Car("Ferrari"); 08
db.Set(car1); 09
StoreImage(car1); 10
Car car2=new Car("BMW"); 11
db.Set(car2); 12
StoreImage(car2); 13
} 14
finally 15
{ 16
db.Close(); 17
} 18
}
01Public Shared Sub StoreCars() 02
File.Delete(YapFileName) 03
Dim db As IObjectContainer = Db4oFactory.OpenFile(YapFileName) 04
Try 05
Dim car1 As Car = New Car("Ferrari") 06
db.Set(car1) 07
StoreImage(car1) 08
Dim car2 As Car = New Car("BMW") 09
db.Set(car2) 10
StoreImage(car2) 11
Finally 12
db.Close() 13
End Try 14
End Sub
01public static void StoreImage(Car car) 02
{ 03
CarImage img = car.CarImage; 04
try 05
{ 06
img.ReadFile(); 07
} 08
catch (Exception ex) 09
{ 10
Console.WriteLine(ex.Message); 11
} 12
}
1Public Shared Sub StoreImage(ByVal car As Car) 2
Dim img As CarImage = car.CarImage 3
Try 4
img.ReadFile() 5
Catch ex As Exception 6
Console.WriteLine(ex.Message) 7
End Try 8
End Sub
CarImage is stored in the database just like normal object, no BLOB data is transferred before explicit call (Blob#readFrom in CarImage#readFile method), which copies the images to the storageFolder.
Please, note, that CarImage reference should be set to the database before uploading actual data. To get the images back to the filesystem we can run a usual query:
01public static void RetrieveCars() 02
{ 03
IObjectContainer db = Db4oFactory.OpenFile(YapFileName); 04
try 05
{ 06
IQuery query = db.Query(); 07
query.Constrain(typeof(Car)); 08
IObjectSet result = query.Execute(); 09
GetImages(result); 10
} 11
finally 12
{ 13
db.Close(); 14
} 15
}
01Public Shared Sub RetrieveCars() 02
Dim db As IObjectContainer = Db4oFactory.OpenFile(YapFileName) 03
Try 04
Dim query As IQuery = db.Query() 05
query.Constrain(GetType(Car)) 06
Dim result As IObjectSet = query.Execute() 07
GetImages(result) 08
Finally 09
db.Close() 10
End Try 11
End Sub
and get BLOB data using retrieved Car references:
01private static void GetImages(IObjectSet result) 02
{ 03
while(result.HasNext()) 04
{ 05
Car car = (Car)(result.Next()); 06
Console.WriteLine(car); 07
CarImage img = car.CarImage; 08
try 09
{ 10
img.WriteFile(); 11
} 12
catch (Exception ex) 13
{ 14
Console.WriteLine(ex.Message); 15
} 16
} 17
}
01Private Shared Sub GetImages(ByVal result As IObjectSet) 02
While result.HasNext() 03
Dim car As Car = CType((result.Next()), Car) 04
Console.WriteLine(car) 05
Dim img As CarImage = car.CarImage 06
Try 07
img.WriteFile() 08
Catch ex As Exception 09
Console.WriteLine(ex.Message) 10
End Try 11
End While 12
End Sub
Retrieved images are placed in CarImage.outFolder ("blobs\out").
So query interface operates on references - no BLOB data is loaded into memory until explicit call (Blob#writeTo). This also means, that activationDepth does not affect Blob objects and best querying performance is achieved without additional coding.