|
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) |
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) |
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.