5. Collections and Arrays


We will slowly move towards real-time data processing now by installing sensors to our car and collecting their output.


namespace com.db4o.f1.chapter3
{   
    using System;
    using System.Text;
    
    public class SensorReadout
    {
        double[] _values;
        DateTime _time;
        Car _car;
        
        public SensorReadout(double[] values, DateTime time, Car car)
        {
            _values = values;
            _time = time;
            _car = car;
        }
        
        public Car Car
        {
            get
            {
                return _car;
            }
        }
        
        public DateTime Time
        {
            get
            {
                return _time;
            }
        }
        
        public int NumValues
        {
            get
            {
                return _values.Length;
            }
        }
        
        public double GetValue(int idx)
        {
            return _values[idx];
        }
        
        override public string ToString()
        {
            StringBuilder builder = new StringBuilder();
            builder.Append(_car);
            builder.Append(" : ");
            builder.Append(_time.TimeOfDay);
            builder.Append(" : ");
            for (int i=0; i<_values.Length; ++i)
            {
                if (i > 0)
                {
                    builder.Append(", ");
                }
                builder.Append(_values[i]);
            }
            return builder.ToString();
        }
    }
}



A car may produce its current sensor readout when requested and keep a list of readouts collected during a race.


namespace com.db4o.f1.chapter3
{
    using System;
    using System.Collections;
    
    public class Car
    {
        string _model;
        Pilot _pilot;
        IList _history;
        
        public Car(string model) : this(model, new ArrayList())
        {
        }
        
        public Car(string model, IList history)
        {
            _model = model;
            _pilot = null;
            _history = history;
        }
        
        public Pilot Pilot
        {
            get
            {
                return _pilot;
            }
            
            set
            {
                _pilot = value;
            }
        }
        
        public string Model
        {
            get
            {
                return _model;
            }
        }
        
        public SensorReadout[] GetHistory()
        {
            SensorReadout[] history = new SensorReadout[_history.Count];
            _history.CopyTo(history, 0);
            return history;
        }
        
        public void Snapshot()
        {
            _history.Add(new SensorReadout(Poll(), DateTime.Now, this));
        }
        
        protected double[]  Poll()
        {
            int factor = _history.Count + 1;
            return new double[] { 0.1d*factor, 0.2d*factor, 0.3d*factor };
        }
        
        override public string ToString()
        {
            return _model + "[" + _pilot + "]/" + _history.Count;
        }
    }
}



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]
    Car car1 = new Car("Ferrari");
        Pilot pilot1 = new Pilot("Michael Schumacher", 100);
        car1.Pilot = pilot1;
        db.set(car1);


    The second car will take two snapshots immediately at startup.


    [storeSecondCar]
    Pilot pilot2 = new Pilot("Rubens Barrichello", 99);
        Car car2 = 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.


      [retrieveAllSensorReadouts]
      SensorReadout proto = new SensorReadout(null, DateTime.MinValue, null);
          ObjectSet result = db.get(proto);
          listResult(result);
      OUTPUT:
      2
      BMW[Rubens Barrichello/99]/2 : 1113883515458 : 0.1,0.2,0.3
      BMW[Rubens Barrichello/99]/2 : 1113883515458 : 0.2,0.4,0.6


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]
SensorReadout proto = new SensorReadout(new double[] { 0.3, 0.1 }, DateTime.MinValue, null);
    ObjectSet result = db.get(proto);
    listResult(result);
OUTPUT:
1
BMW[Rubens Barrichello/99]/2 : 1113883515458 : 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]
SensorReadout protoreadout = new SensorReadout(new double[] { 0.6, 0.2 }, DateTime.MinValue, null);
    IList protohistory = new ArrayList();
    protohistory.Add(protoreadout);
    Car protocar = new Car(null, protohistory);
    ObjectSet result = 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]
ObjectSet result = db.get(new ArrayList());
    listResult(result);
OUTPUT:
2
[]
[BMW[Rubens Barrichello/99]/2 : 1113883515458 : 0.1,0.2,0.3, BMW[Rubens Barrichello/99]/2 : 1113883515458 : 0.2,0.4,0.6]


This doesn't work with arrays, though.


[retrieveArrays]
ObjectSet result = db.get(new double[] { 0.6, 0.4 });
    listResult(result);
OUTPUT:
0



5.2.2. Query API


Handling of arrays and collections is analogous to the previous example.


[retrieveSensorReadoutQuery]
Query query = db.query();
    query.constrain(typeof(SensorReadout));
    Query valuequery = query.descend("_values");
    valuequery.constrain(0.3);
    valuequery.constrain(0.1);
    ObjectSet result = query.execute();
    listResult(result);
OUTPUT:
1
BMW[Rubens Barrichello/99]/2 : 1113883515458 : 0.1,0.2,0.3



[retrieveCarQuery]
Query query = db.query();
    query.constrain(typeof(Car));
    Query historyquery = query.descend("_history");
    historyquery.constrain(typeof(SensorReadout));
    Query valuequery = historyquery.descend("_values");
    valuequery.constrain(0.3);
    valuequery.constrain(0.1);
    ObjectSet result = query.execute();
    listResult(result);
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]
Db4o.configure().objectClass(typeof(Car)).cascadeOnUpdate(true);



[updateCarPart2]
ObjectSet result = db.get(new Car("BMW", null));
    Car car = (Car)result.next();
    car.Snapshot();
    db.set(car);
    retrieveAllSensorReadouts(db);
OUTPUT:
3
BMW[Rubens Barrichello/99]/3 : 1113883515458 : 0.1,0.2,0.3
BMW[Rubens Barrichello/99]/3 : 1113883515723 : 0.30000000000000004,0.6000000000000001,0.8999999999999999
BMW[Rubens Barrichello/99]/3 : 1113883515458 : 0.2,0.4,0.6


There's nothing special about deleting arrays and collections, too.

Deleting an object from a collection is an update, too, of course.


[updateCollection]
Query query = db.query();
    query.constrain(typeof(Car));
    ObjectSet result = query.descend("_history").execute();
    IList coll = (IList)result.next();
    coll.RemoveAt(0);
    db.set(coll);
    Car proto = new Car(null, null);
    result = db.get(proto);
    while (result.hasNext())
    {
        Car car = (Car)result.next();
        foreach (object readout in car.GetHistory())
        {
            Console.WriteLine(readout);
        }
    }
OUTPUT:
BMW[Rubens Barrichello/99]/2 : 1113883515458 : 0.2,0.4,0.6
BMW[Rubens Barrichello/99]/2 : 1113883515723 : 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]
Db4o.configure().objectClass(typeof(Car)).cascadeOnDelete(true);



[deleteAllPart2]
ObjectSet result = db.get(new Car(null, null));
    while (result.hasNext())
    {
        db.delete(result.next());
    }
    ObjectSet readouts = db.get(new SensorReadout(null, DateTime.MinValue, null));
    while(readouts.hasNext())
    {
        db.delete(readouts.next());
    }



5.4. db4o custom collections


db4o also provides customized collection implementations, tweaked for use with db4o. We will get to that in a later chapter when we have finished our first walkthrough.


5.5. 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.6. Full source



namespace com.db4o.f1.chapter3
{
    using System;
    using System.Collections;
    using System.IO;
    using com.db4o;
    using com.db4o.query;
    
    public class CollectionsExample : Util
    {
        public static void Main(string[] args)
        {
            File.Delete(Util.YapFileName);            
            ObjectContainer db = Db4o.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 = Db4o.openFile(Util.YapFileName);
                updateCarPart2(db);
                updateCollection(db);
                db.close();
                deleteAllPart1();
                db=Db4o.openFile(Util.YapFileName);
                deleteAllPart2(db);
                retrieveAllSensorReadouts(db);
            }
            finally
            {
                db.close();
            }
        }
        
        public static void storeFirstCar(ObjectContainer db)
        {
            Car car1 = new Car("Ferrari");
            Pilot pilot1 = new Pilot("Michael Schumacher", 100);
            car1.Pilot = pilot1;
            db.set(car1);
        }
        
        public static void storeSecondCar(ObjectContainer db)
        {
            Pilot pilot2 = new Pilot("Rubens Barrichello", 99);
            Car car2 = new Car("BMW");
            car2.Pilot = pilot2;
            car2.Snapshot();
            car2.Snapshot();
            db.set(car2);       
        }
        
        public static void retrieveAllSensorReadouts(ObjectContainer db)
        {
            SensorReadout proto = new SensorReadout(null, DateTime.MinValue, null);
            ObjectSet result = db.get(proto);
            listResult(result);
        }
        
        public static void retrieveSensorReadoutQBE(ObjectContainer db)
        {
            SensorReadout proto = new SensorReadout(new double[] { 0.3, 0.1 }, DateTime.MinValue, null);
            ObjectSet result = db.get(proto);
            listResult(result);
        }
        
        public static void retrieveCarQBE(ObjectContainer db)
        {
            SensorReadout protoreadout = new SensorReadout(new double[] { 0.6, 0.2 }, DateTime.MinValue, null);
            IList protohistory = new ArrayList();
            protohistory.Add(protoreadout);
            Car protocar = new Car(null, protohistory);
            ObjectSet result = db.get(protocar);
            listResult(result);
        }
        
        public static void retrieveCollections(ObjectContainer db)
        {
            ObjectSet result = db.get(new ArrayList());
            listResult(result);
        }
        
        public static void retrieveArrays(ObjectContainer db)
        {
            ObjectSet result = db.get(new double[] { 0.6, 0.4 });
            listResult(result);
        }
        
        public static void retrieveSensorReadoutQuery(ObjectContainer db)
        {
            Query query = db.query();
            query.constrain(typeof(SensorReadout));
            Query valuequery = query.descend("_values");
            valuequery.constrain(0.3);
            valuequery.constrain(0.1);
            ObjectSet result = query.execute();
            listResult(result);
        }
        
        public static void retrieveCarQuery(ObjectContainer db)
        {
            Query query = db.query();
            query.constrain(typeof(Car));
            Query historyquery = query.descend("_history");
            historyquery.constrain(typeof(SensorReadout));
            Query valuequery = historyquery.descend("_values");
            valuequery.constrain(0.3);
            valuequery.constrain(0.1);
            ObjectSet result = query.execute();
            listResult(result);
        }
        
        public static void updateCarPart1()
        {
            Db4o.configure().objectClass(typeof(Car)).cascadeOnUpdate(true);
        }
        
        public static void updateCarPart2(ObjectContainer db)
        {
            ObjectSet result = db.get(new Car("BMW", null));
            Car car = (Car)result.next();
            car.Snapshot();
            db.set(car);
            retrieveAllSensorReadouts(db);
        }
        
        public static void updateCollection(ObjectContainer db)
        {
            Query query = db.query();
            query.constrain(typeof(Car));
            ObjectSet result = query.descend("_history").execute();
            IList coll = (IList)result.next();
            coll.RemoveAt(0);
            db.set(coll);
            Car proto = new Car(null, null);
            result = db.get(proto);
            while (result.hasNext())
            {
                Car car = (Car)result.next();
                foreach (object readout in car.GetHistory())
                {
                    Console.WriteLine(readout);
                }
            }
        }
        
        public static void deleteAllPart1()
        {
            Db4o.configure().objectClass(typeof(Car)).cascadeOnDelete(true);
        }

        public static void deleteAllPart2(ObjectContainer db)
        {
            ObjectSet result = db.get(new Car(null, null));
            while (result.hasNext())
            {
                db.delete(result.next());
            }
            ObjectSet readouts = db.get(new SensorReadout(null, DateTime.MinValue, null));
            while(readouts.hasNext())
            {
                db.delete(readouts.next());
            }
        }
    }
}





--
generated by
Doctor courtesy of db4objecs Inc.