| # 5. Collections and Arrays We will slowly move towards real-time data processing now by installing sensors to our car and collecting their output.
`Imports System Imports System.Text Namespace com.db4o.f1.chapter3 Public Class SensorReadout Private _values As Double() Private _time As DateTime Private _car As Car Public Sub New(ByVal values As Double(), ByVal time As DateTime, ByVal car As Car) _values = values _time = time _car = car End Sub Public ReadOnly Property Car() As Car Get Return _car End Get End Property Public ReadOnly Property Time() As DateTime Get Return _time End Get End Property Public ReadOnly Property NumValues() As Integer Get Return _values.Length End Get End Property Public ReadOnly Property Values() As Double() Get Return _values End Get End Property Public Function GetValue(ByVal idx As Integer) As Double Return _values(idx) End Function Public Overloads Overrides Function ToString() As String Dim builder As StringBuilder = New StringBuilder() builder.Append(_car) builder.Append(" : ") builder.Append(_time.TimeOfDay) builder.Append(" : ") Dim i As Integer = 0 While i < _values.Length If i > 0 Then builder.Append(", ") End If builder.Append(_values(i)) System.Threading.Interlocked.Increment(i) End While Return builder.ToString() End Function End Class End Namespace`
A car may produce its current sensor readout when requested and keep a list of readouts collected during a race.
`Imports System Imports System.Collections Namespace com.db4o.f1.chapter3 Public Class Car Private _model As String Private _pilot As Pilot Private _history As IList Public Sub New(ByVal model As String) Me.New(model, New ArrayList()) End Sub Public Sub New(ByVal model As String, ByVal history As IList) _model = model _pilot = Nothing _history = history End Sub Public Property Pilot() As Pilot Get Return _pilot End Get Set _pilot = value End Set End Property Public ReadOnly Property Model() As String Get Return _model End Get End Property Public ReadOnly Property History() As IList Get Return _history End Get End Property Public Sub Snapshot() _history.Add(New SensorReadout(Poll(), DateTime.Now, Me)) End Sub Protected Function Poll() As Double() Dim factor As Integer = _history.Count + 1 Return New Double() {0.1 * factor, 0.2 * factor, 0.3 * factor} End Function Public Overloads Overrides Function ToString() As String Return String.Format("{0}[{1}]/{2}", _model, _pilot, _history.Count) End Function End Class End Namespace`
We will constrain ourselves to rather static data at the moment and add flexibility during the next chapters. ## 5.1. Storing This should be familiar by now.
`[storeFirstCar] Dim car1 As Car = New Car("Ferrari") Dim pilot1 As Pilot = New Pilot("Michael Schumacher", 100) car1.Pilot = pilot1 db.[Set](car1)`
The second car will take two snapshots immediately at startup.
`[storeSecondCar] Dim pilot2 As Pilot = New Pilot("Rubens Barrichello", 99) Dim car2 As Car = New Car("BMW") car2.Pilot = pilot2 car2.Snapshot() car2.Snapshot() db.[Set](car2)`
## 5.2. Retrieving ## 5.2.1. QBE First let us verify that we indeed have taken snapshots.
`[retrieveAllSensorReadout] Dim result As ObjectSet = db.[Get](GetType(SensorReadout)) ListResult(result)`
OUTPUT: 2 BMW[Rubens Barrichello/99]/2 : 1152088427384 : 0.2,0.4,0.6 BMW[Rubens Barrichello/99]/2 : 1152088427384 : 0.1,0.2,0.3

As a prototype for an array, we provide an array of the same type, containing only the values we expect the result to contain.

`[retrieveSensorReadoutQBE] Dim proto As SensorReadout = New SensorReadout(New Double() {0.3, 0.1}, DateTime.MinValue, Nothing) Dim result As ObjectSet = db.[Get](proto) ListResult(result)`

OUTPUT: 1 BMW[Rubens Barrichello/99]/2 : 1152088427384 : 0.1,0.2,0.3

Note that the actual position of the given elements in the prototype array is irrelevant.
To retrieve a car by its stored sensor readouts, we install a history containing the sought-after values.

`[retrieveCarQBE] Dim protoReadout As SensorReadout = New SensorReadout(New Double() {0.6, 0.2}, DateTime.MinValue, Nothing) Dim protoHistory As IList = New ArrayList() protoHistory.Add(protoReadout) Dim protoCar As Car = New Car(Nothing, protoHistory) Dim result As ObjectSet = db.[Get](protoCar) ListResult(result)`

OUTPUT: 1 BMW[Rubens Barrichello/99]/2

We can also query for the collections themselves, since they are first class objects.

`[retrieveCollections] Dim result As ObjectSet = db.[Get](New ArrayList()) ListResult(result)`

OUTPUT: 2 [] [BMW[Rubens Barrichello/99]/2 : 1152088427384 : 0.1,0.2,0.3, BMW[Rubens Barrichello/99]/2 : 1152088427384 : 0.2,0.4,0.6]

This doesn't work with arrays, though.

`[retrieveArrays] Dim result As ObjectSet = db.[Get](New Double() {0.6, 0.4}) ListResult(result)`

OUTPUT: 0

## 5.2.2. Native Queries

If we want to use Native Queries to find SensorReadouts with matching values, we simply write this as if we would check every single instance:

`Public Class RetrieveSensorReadoutPredicate Inherits Predicate Public Function Match(ByVal candidate As SensorReadout) As Boolean Return Array.IndexOf(candidate.Values, 0.3) > - 1 AndAlso Array.IndexOf(candidate.Values, 0.1) > - 1 End Function End Class`

`[retrieveSensorReadoutNative] Dim results As ObjectSet = db.Query(New RetrieveSensorReadoutPredicate()) ListResult(results)`

OUTPUT: 0

And here's how we find Cars with matching readout values:

`Public Class RetrieveCarPredicate Inherits Predicate Public Function Match(ByVal car As Car) As Boolean For Each sensor As SensorReadout In car.History If Array.IndexOf(sensor.Values, 0.3) > - 1 AndAlso Array.IndexOf(sensor.Values, 0.1) > - 1 Then Return True End If Next Return False End Function End Class`

`[retrieveCarNative] Dim results As ObjectSet = db.Query(New RetrieveCarPredicate()) ListResult(results)`

OUTPUT: 1 BMW[Rubens Barrichello/99]/2

## 5.2.3. Query API

Handling of arrays and collections is analogous to the previous example. First, lets retrieve only the SensorReadouts with specific values:

`[retrieveSensorReadoutQuery] Dim query As Query = db.Query() query.Constrain(GetType(SensorReadout)) Dim valueQuery As Query = query.Descend("_values") valueQuery.Constrain(0.3) valueQuery.Constrain(0.1) Dim results As ObjectSet = query.Execute() ListResult(results)`

OUTPUT: 1 BMW[Rubens Barrichello/99]/2 : 1152088427384 : 0.1,0.2,0.3

Then let's get some Cars with matching Readout values:

`[retrieveCarQuery] Dim query As Query = db.Query() query.Constrain(GetType(Car)) Dim historyQuery As Query = query.Descend("_history") historyQuery.Constrain(GetType(SensorReadout)) Dim valueQuery As Query = historyQuery.Descend("_values") valueQuery.Constrain(0.3) valueQuery.Constrain(0.1) Dim results As ObjectSet = query.Execute() ListResult(results)`

OUTPUT: 1 BMW[Rubens Barrichello/99]/2

## 5.3. Updating and deleting

This should be familiar, we just have to remember to take care of the update depth.

`[updateCarPart1] Db4oFactory.Configure().ObjectClass(GetType(Car)).CascadeOnUpdate(True)`

`[updateCarPart2] Dim result As ObjectSet = db.[Get](New Car("BMW", Nothing)) Dim car As Car = DirectCast(result.[Next](), Car) car.Snapshot() db.[Set](car) RetrieveAllSensorReadouts(db)`

OUTPUT: 3 BMW[Rubens Barrichello/99]/3 : 1152088428183 : 0.30000000000000004,0.6000000000000001,0.8999999999999999 BMW[Rubens Barrichello/99]/3 : 1152088427384 : 0.2,0.4,0.6 BMW[Rubens Barrichello/99]/3 : 1152088427384 : 0.1,0.2,0.3

There's nothing special about deleting arrays and collections, too.
Deleting an object from a collection is an update, too, of course.

`[updateCollection] Dim query As Query = db.Query() query.Constrain(GetType(Car)) Dim result As ObjectSet = query.Descend("_history").Execute() Dim history As IList = DirectCast(result.[Next](), IList) history.RemoveAt(0) db.[Set](history) Dim proto As Car = New Car(Nothing, Nothing) result = db.[Get](proto) For Each car As Car In result For Each readout As Object In car.History Console.WriteLine(readout) Next Next`

OUTPUT: BMW[Rubens Barrichello/99]/2 : 1152088427384 : 0.2,0.4,0.6 BMW[Rubens Barrichello/99]/2 : 1152088428183 : 0.30000000000000004,0.6000000000000001,0.8999999999999999

(This example also shows that with db4o it is quite easy to access object internals we were never meant to see. Please keep this always in mind and be careful.)
We will delete all cars from the database again to prepare for the next chapter.

`[deleteAllPart1] Db4oFactory.Configure().ObjectClass(GetType(Car)).CascadeOnDelete(True)`

`[deleteAllPart2] Dim result As ObjectSet = db.[Get](New Car(Nothing, Nothing)) For Each car As Object In result db.Delete(car) Next Dim readouts As ObjectSet = db.[Get](New SensorReadout(Nothing, DateTime.MinValue, Nothing)) For Each readout As Object In readouts db.Delete(readout) Next`

## 5.4. Conclusion

Ok, collections are just objects. But why did we have to specify the concrete ArrayList type all the way? Was that necessary? How does db4o handle inheritance? We will cover that in the next chapter.

## 5.5. Full source

`Imports System Imports System.Collections Imports System.IO Imports com.db4o Imports com.db4o.query Namespace com.db4o.f1.chapter3 Public Class CollectionsExample Inherits Util Public Shared Sub Main(ByVal args As String()) File.Delete(Util.YapFileName) Dim db As ObjectContainer = Db4oFactory.OpenFile(Util.YapFileName) Try StoreFirstCar(db) StoreSecondCar(db) RetrieveAllSensorReadouts(db) RetrieveSensorReadoutQBE(db) RetrieveCarQBE(db) RetrieveCollections(db) RetrieveArrays(db) RetrieveSensorReadoutQuery(db) RetrieveCarQuery(db) db.Close() UpdateCarPart1() db = Db4oFactory.OpenFile(Util.YapFileName) UpdateCarPart2(db) UpdateCollection(db) db.Close() DeleteAllPart1() db = Db4oFactory.OpenFile(Util.YapFileName) DeleteAllPart2(db) RetrieveAllSensorReadouts(db) Finally db.Close() End Try End Sub Public Shared Sub StoreFirstCar(ByVal db As ObjectContainer) Dim car1 As Car = New Car("Ferrari") Dim pilot1 As Pilot = New Pilot("Michael Schumacher", 100) car1.Pilot = pilot1 db.[Set](car1) End Sub Public Shared Sub StoreSecondCar(ByVal db As ObjectContainer) Dim pilot2 As Pilot = New Pilot("Rubens Barrichello", 99) Dim car2 As Car = New Car("BMW") car2.Pilot = pilot2 car2.Snapshot() car2.Snapshot() db.[Set](car2) End Sub Public Shared Sub RetrieveAllSensorReadouts(ByVal db As ObjectContainer) Dim result As ObjectSet = db.[Get](GetType(SensorReadout)) ListResult(result) End Sub Public Shared Sub RetrieveSensorReadoutQBE(ByVal db As ObjectContainer) Dim proto As SensorReadout = New SensorReadout(New Double() {0.3, 0.1}, DateTime.MinValue, Nothing) Dim result As ObjectSet = db.[Get](proto) ListResult(result) End Sub Public Shared Sub RetrieveCarQBE(ByVal db As ObjectContainer) Dim protoReadout As SensorReadout = New SensorReadout(New Double() {0.6, 0.2}, DateTime.MinValue, Nothing) Dim protoHistory As IList = New ArrayList() protoHistory.Add(protoReadout) Dim protoCar As Car = New Car(Nothing, protoHistory) Dim result As ObjectSet = db.[Get](protoCar) ListResult(result) End Sub Public Shared Sub RetrieveCollections(ByVal db As ObjectContainer) Dim result As ObjectSet = db.[Get](New ArrayList()) ListResult(result) End Sub Public Shared Sub RetrieveArrays(ByVal db As ObjectContainer) Dim result As ObjectSet = db.[Get](New Double() {0.6, 0.4}) ListResult(result) End Sub Public Shared Sub RetrieveSensorReadoutQuery(ByVal db As ObjectContainer) Dim query As Query = db.Query() query.Constrain(GetType(SensorReadout)) Dim valueQuery As Query = query.Descend("_values") valueQuery.Constrain(0.3) valueQuery.Constrain(0.1) Dim results As ObjectSet = query.Execute() ListResult(results) End Sub Public Shared Sub RetrieveCarQuery(ByVal db As ObjectContainer) Dim query As Query = db.Query() query.Constrain(GetType(Car)) Dim historyQuery As Query = query.Descend("_history") historyQuery.Constrain(GetType(SensorReadout)) Dim valueQuery As Query = historyQuery.Descend("_values") valueQuery.Constrain(0.3) valueQuery.Constrain(0.1) Dim results As ObjectSet = query.Execute() ListResult(results) End Sub Public Class RetrieveSensorReadoutPredicate Inherits Predicate Public Function Match(ByVal candidate As SensorReadout) As Boolean Return Array.IndexOf(candidate.Values, 0.3) > - 1 AndAlso Array.IndexOf(candidate.Values, 0.1) > - 1 End Function End Class Public Shared Sub RetrieveSensorReadoutNative(ByVal db As ObjectContainer) Dim results As ObjectSet = db.Query(New RetrieveSensorReadoutPredicate()) ListResult(results) End Sub Public Class RetrieveCarPredicate Inherits Predicate Public Function Match(ByVal car As Car) As Boolean For Each sensor As SensorReadout In car.History If Array.IndexOf(sensor.Values, 0.3) > - 1 AndAlso Array.IndexOf(sensor.Values, 0.1) > - 1 Then Return True End If Next Return False End Function End Class Public Shared Sub RetrieveCarNative(ByVal db As ObjectContainer) Dim results As ObjectSet = db.Query(New RetrieveCarPredicate()) ListResult(results) End Sub Public Shared Sub UpdateCarPart1() Db4oFactory.Configure().ObjectClass(GetType(Car)).CascadeOnUpdate(True) End Sub Public Shared Sub UpdateCarPart2(ByVal db As ObjectContainer) Dim result As ObjectSet = db.[Get](New Car("BMW", Nothing)) Dim car As Car = DirectCast(result.[Next](), Car) car.Snapshot() db.[Set](car) RetrieveAllSensorReadouts(db) End Sub Public Shared Sub UpdateCollection(ByVal db As ObjectContainer) Dim query As Query = db.Query() query.Constrain(GetType(Car)) Dim result As ObjectSet = query.Descend("_history").Execute() Dim history As IList = DirectCast(result.[Next](), IList) history.RemoveAt(0) db.[Set](history) Dim proto As Car = New Car(Nothing, Nothing) result = db.[Get](proto) For Each car As Car In result For Each readout As Object In car.History Console.WriteLine(readout) Next Next End Sub Public Shared Sub DeleteAllPart1() Db4oFactory.Configure().ObjectClass(GetType(Car)).CascadeOnDelete(True) End Sub Public Shared Sub DeleteAllPart2(ByVal db As ObjectContainer) Dim result As ObjectSet = db.[Get](New Car(Nothing, Nothing)) For Each car As Object In result db.Delete(car) Next Dim readouts As ObjectSet = db.[Get](New SensorReadout(Nothing, DateTime.MinValue, Nothing)) For Each readout As Object In readouts db.Delete(readout) Next End Sub End Class End Namespace`

--
generated by Doctor courtesy of db4objects Inc.