7. Inheritance


So far we have always been working with the concrete (i.e. most specific type of an object. What about subclassing and interfaces?

To explore this, we will differentiate between different kinds of sensors.

using System;
namespace Db4odoc.Tutorial.F1.Chapter5
{   
    public class SensorReadout
    {
        DateTime _time;
        Car _car;
        string _description;
        
        public SensorReadout(DateTime time, Car car, string description)
        {
            _time = time;
            _car = car;
            _description = description;
        }
        
        public Car Car
        {
            get
            {
                return _car;
            }
        }
        
        public DateTime Time
        {
            get
            {
                return _time;
            }
        }
        
        public string Description
        {
            get
            {
                return _description;
            }
        }
        
        override public string ToString()
        {
            return string.Format("{0}:{1}:{2}", _car, _time, _description);
        }
    }
}


using System;
namespace Db4odoc.Tutorial.F1.Chapter5
{   
    public class TemperatureSensorReadout : SensorReadout
    {
        double _temperature;
        public TemperatureSensorReadout(DateTime time, Car car, string description, double temperature)
            : base(time, car, description)
        {
            _temperature = temperature;
        }
        
        public double Temperature
        {
            get
            {
                return _temperature;
            }
        }
        
        override public string ToString()
        {
            return string.Format("{0} temp: {1}", base.ToString(), _temperature);
        }
    }
}


using System;
namespace Db4odoc.Tutorial.F1.Chapter5
{
    public class PressureSensorReadout : SensorReadout
    {
        double _pressure;
        
        public PressureSensorReadout(DateTime time, Car car, string description, double pressure)
            : base(time, car, description)
        {
            _pressure = pressure;
        }
        
        public double Pressure
        {
            get
            {
                return _pressure;
            }
        }
        
        override public string ToString()
        {
            return string.Format("{0} pressure: {1}", base.ToString(), _pressure);
        }
    }
}


Our car's snapshot mechanism is changed accordingly.

using System;
using System.Collections;
namespace Db4odoc.Tutorial.F1.Chapter5
{   
    public class Car
    {
        string _model;
        Pilot _pilot;
        IList _history;
        
        public Car(string model)
        {
            _model = model;
            _pilot = null;
            _history = new ArrayList();
        }
        
        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 TemperatureSensorReadout(DateTime.Now, this, "oil", PollOilTemperature()));
            _history.Add(new TemperatureSensorReadout(DateTime.Now, this, "water", PollWaterTemperature()));
            _history.Add(new PressureSensorReadout(DateTime.Now, this, "oil", PollOilPressure()));
        }
        
        protected double PollOilTemperature()
        {
            return 0.1*_history.Count;
        }
        
        protected double PollWaterTemperature()
        {
            return 0.2*_history.Count;
        }
        
        protected double PollOilPressure()
        {
            return 0.3*_history.Count;
        }
        
        override public string ToString()
        {
            return string.Format("{0}[{1}]/{2}", _model, _pilot, _history.Count);
        }
    }
}



    7.1. Storing


    Our setup code has not changed at all, just the internal workings of a snapshot.

    // storeFirstCar
    Car car1 = new Car("Ferrari");
    Pilot pilot1 = new Pilot("Michael Schumacher", 100);
    car1.Pilot = pilot1;
    db.Store(car1);


    // storeSecondCar
    Pilot pilot2 = new Pilot("Rubens Barrichello", 99);
    Car car2 = new Car("BMW");
    car2.Pilot = pilot2;
    car2.Snapshot();
    car2.Snapshot();
    db.Store(car2);



    7.2. Retrieving


    db4o will provide us with all objects of the given type. To collect all instances of a given class, no matter whether they are subclass members or direct instances, we just provide a corresponding prototype.

    // retrieveTemperatureReadoutsQBE
    SensorReadout proto = new TemperatureSensorReadout(DateTime.MinValue, null, null, 0.0);
    IObjectSet result = db.QueryByExample(proto);
    ListResult(result);


    // retrieveAllSensorReadoutsQBE
    SensorReadout proto = new SensorReadout(DateTime.MinValue, null, null);
    IObjectSet result = db.QueryByExample(proto);
    ListResult(result);


    This is one more situation where QBE might not be applicable: What if the given type is an interface or an abstract class? Well, there's a little trick to keep in mind: Type objects receive special handling with QBE.

    // retrieveAllSensorReadoutsQBEAlternative
    IObjectSet result = db.QueryByExample(typeof(SensorReadout));
    ListResult(result);


    And of course there's our SODA API:

    // retrieveAllSensorReadoutsQuery
    IQuery query = db.Query();
    query.Constrain(typeof(SensorReadout));
    IObjectSet result = query.Execute();
    ListResult(result);



    7.3. Updating and deleting


    is just the same for all objects, no matter where they are situated in the inheritance tree.

    Just like we retrieved all objects from the database above, we can delete all stored objects to prepare for the next chapter.

    // deleteAll
    IObjectSet result = db.QueryByExample(typeof(Object));
    foreach (object item in result)
    {
        db.Delete(item);
    }



    7.4. Conclusion


    Now we have covered all basic OO features and the way they are handled by db4o. We will complete the first part of our db4o walkthrough in the next chapter   by looking at deep object graphs, including recursive structures.


    7.5. Full source


    using System;
    using System.IO;
    using Db4objects.Db4o;
    using Db4objects.Db4o.Query;
    namespace Db4odoc.Tutorial.F1.Chapter5
    {   
        public class InheritanceExample : Util
        {
            readonly static string YapFileName = Path.Combine(
                                   Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
                                   "formula1.yap");  
            
            public static void Main(string[] args)
            {
                File.Delete(YapFileName);
                using(IObjectContainer db = Db4oEmbedded.OpenFile(YapFileName))
                {
                    StoreFirstCar(db);
                    StoreSecondCar(db);
                    RetrieveTemperatureReadoutsQBE(db);
                    RetrieveAllSensorReadoutsQBE(db);
                    RetrieveAllSensorReadoutsQBEAlternative(db);
                    RetrieveAllSensorReadoutsQuery(db);
                    RetrieveAllObjects(db);
                }
            }
            
            public static void StoreFirstCar(IObjectContainer db)
            {
                Car car1 = new Car("Ferrari");
                Pilot pilot1 = new Pilot("Michael Schumacher", 100);
                car1.Pilot = pilot1;
                db.Store(car1);
            }
            
            public static void StoreSecondCar(IObjectContainer db)
            {
                Pilot pilot2 = new Pilot("Rubens Barrichello", 99);
                Car car2 = new Car("BMW");
                car2.Pilot = pilot2;
                car2.Snapshot();
                car2.Snapshot();
                db.Store(car2);
            }
            
            public static void RetrieveAllSensorReadoutsQBE(IObjectContainer db)
            {
                SensorReadout proto = new SensorReadout(DateTime.MinValue, null, null);
                IObjectSet result = db.QueryByExample(proto);
                ListResult(result);
            }
            
            public static void RetrieveTemperatureReadoutsQBE(IObjectContainer db)
            {
                SensorReadout proto = new TemperatureSensorReadout(DateTime.MinValue, null, null, 0.0);
                IObjectSet result = db.QueryByExample(proto);
                ListResult(result);
            }
            
            public static void RetrieveAllSensorReadoutsQBEAlternative(IObjectContainer db)
            {
                IObjectSet result = db.QueryByExample(typeof(SensorReadout));
                ListResult(result);
            }
            
            public static void RetrieveAllSensorReadoutsQuery(IObjectContainer db)
            {
                IQuery query = db.Query();
                query.Constrain(typeof(SensorReadout));
                IObjectSet result = query.Execute();
                ListResult(result);
            }
            
            public static void RetrieveAllObjects(IObjectContainer db)
            {
                IObjectSet result = db.QueryByExample(new object());
                ListResult(result);
            }
        }
    }