<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <link rel="stylesheet" type="text/css" href="docs.css"> <!--[if gte IE 5]> <link href="docs_ie.css" rel="stylesheet" type="text/css"> <![endif]--> </head> <body><div id="pagecontainer"><table><tr><td width="5"> </td><td><a name="Collections"></a><br> <a name="outline174"></a><br><h1>6. Collections and Arrays</h1><br> We will slowly move towards real-time data processing now by installing sensors to our car and collecting their output.<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>using System;<br> using System.Text;<br> <br> namespace Db4odoc.Tutorial.F1.Chapter4<br> { <br> public class SensorReadout<br> {<br> double[] _values;<br> DateTime _time;<br> Car _car;<br> <br> public SensorReadout(double[] values, DateTime time, Car car)<br> {<br> _values = values;<br> _time = time;<br> _car = car;<br> }<br> <br> public Car Car<br> {<br> get<br> {<br> return _car;<br> }<br> }<br> <br> public DateTime Time<br> {<br> get<br> {<br> return _time;<br> }<br> }<br> <br> public int NumValues<br> {<br> get<br> {<br> return _values.Length;<br> }<br> }<br> <br> public double[] Values<br> {<br> get<br> {<br> return _values;<br> }<br> }<br> <br> public double GetValue(int idx)<br> {<br> return _values[idx];<br> }<br> <br> override public string ToString()<br> {<br> StringBuilder builder = new StringBuilder();<br> builder.Append(_car);<br> builder.Append(" : ");<br> builder.Append(_time.TimeOfDay);<br> builder.Append(" : ");<br> for (int i=0; i<_values.Length; ++i)<br> {<br> if (i > 0)<br> {<br> builder.Append(", ");<br> }<br> builder.Append(_values[i]);<br> }<br> return builder.ToString();<br> }<br> }<br> }<br> </code></td></tr></table> <br> <br> A car may produce its current sensor readout when requested and keep a list of readouts collected during a race.<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>using System;<br> using System.Collections;<br> <br> namespace Db4odoc.Tutorial.F1.Chapter4<br> {<br> public class Car<br> {<br> string _model;<br> Pilot _pilot;<br> IList _history;<br> <br> public Car(string model) : this(model, new ArrayList())<br> {<br> }<br> <br> public Car(string model, IList history)<br> {<br> _model = model;<br> _pilot = null;<br> _history = history;<br> }<br> <br> public Pilot Pilot<br> {<br> get<br> {<br> return _pilot;<br> }<br> <br> set<br> {<br> _pilot = value;<br> }<br> }<br> <br> public string Model<br> {<br> get<br> {<br> return _model;<br> }<br> }<br> <br> public IList History<br> {<br> get<br> {<br> return _history;<br> }<br> }<br> <br> public void Snapshot()<br> {<br> _history.Add(new SensorReadout(Poll(), DateTime.Now, this));<br> }<br> <br> protected double[] Poll()<br> {<br> int factor = _history.Count + 1;<br> return new double[] { 0.1d*factor, 0.2d*factor, 0.3d*factor };<br> }<br> <br> override public string ToString()<br> {<br> return string.Format("{0}[{1}]/{2}", _model, _pilot, _history.Count);<br> }<br> }<br> }<br> </code></td></tr></table> <br> <br> We will constrain ourselves to rather static data at the moment and add flexibility during the next chapters.<br> <br> <ul> <a name="outline175"></a><br><h2>6.1. Storing</h2><br> This should be familiar by now.<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// storeFirstCar<br> Car car1 = new Car("Ferrari");<br> Pilot pilot1 = new Pilot("Michael Schumacher", 100);<br> car1.Pilot = pilot1;<br> db.Store(car1);</code></td><td class="lg" align="left" valign="bottom" width=43><input type='button' class='button' value='Run' onclick='window.external.RunExample("com.db4odoc.f1.chapter4.CollectionsExample", "storeFirstCar")' /></td></tr></table> <br> <br> The second car will take two snapshots immediately at startup.<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// storeSecondCar<br> Pilot pilot2 = new Pilot("Rubens Barrichello", 99);<br> Car car2 = new Car("BMW");<br> car2.Pilot = pilot2;<br> car2.Snapshot();<br> car2.Snapshot();<br> db.Store(car2);</code></td><td class="lg" align="left" valign="bottom" width=43><input type='button' class='button' value='Run' onclick='window.external.RunExample("com.db4odoc.f1.chapter4.CollectionsExample", "storeSecondCar")' /></td></tr></table> <br> <br> <a name="outline176"></a><br><h2>6.2. Retrieving</h2><br> <ul> <a name="outline177"></a><br><h2>6.2.1. QBE</h2><br> First let us verify that we indeed have taken snapshots.<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// retrieveAllSensorReadout<br> IObjectSet result = db.QueryByExample(typeof(SensorReadout));<br> ListResult(result);</code></td><td class="lg" align="left" valign="bottom" width=43><input type='button' class='button' value='Run' onclick='window.external.RunExample("com.db4odoc.f1.chapter4.CollectionsExample", "retrieveAllSensorReadout")' /></td></tr></table> <br> <br> As a prototype for an array, we provide an array of the same type, containing only the values we expect the result to contain.<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// retrieveSensorReadoutQBE<br> SensorReadout proto = new SensorReadout(new double[] { 0.3, 0.1 }, DateTime.MinValue, null);<br> IObjectSet result = db.QueryByExample(proto);<br> ListResult(result);</code></td><td class="lg" align="left" valign="bottom" width=43><input type='button' class='button' value='Run' onclick='window.external.RunExample("com.db4odoc.f1.chapter4.CollectionsExample", "retrieveSensorReadoutQBE")' /></td></tr></table> <br> <br> Note that the actual position of the given elements in the prototype array is irrelevant.<br> <br> To retrieve a car by its stored sensor readouts, we install a history containing the sought-after values.<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// retrieveCarQBE<br> SensorReadout protoReadout = new SensorReadout(new double[] { 0.6, 0.2 }, DateTime.MinValue, null);<br> IList protoHistory = new ArrayList();<br> protoHistory.Add(protoReadout);<br> Car protoCar = new Car(null, protoHistory);<br> IObjectSet result = db.QueryByExample(protoCar);<br> ListResult(result);</code></td><td class="lg" align="left" valign="bottom" width=43><input type='button' class='button' value='Run' onclick='window.external.RunExample("com.db4odoc.f1.chapter4.CollectionsExample", "retrieveCarQBE")' /></td></tr></table> <br> <br> We can also query for the collections themselves, since they are first class objects.<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// retrieveCollections<br> IObjectSet result = db.QueryByExample(new ArrayList());<br> ListResult(result);</code></td><td class="lg" align="left" valign="bottom" width=43><input type='button' class='button' value='Run' onclick='window.external.RunExample("com.db4odoc.f1.chapter4.CollectionsExample", "retrieveCollections")' /></td></tr></table> <br> <br> This doesn't work with arrays, though.<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// retrieveArrays<br> IObjectSet result = db.QueryByExample(new double[] { 0.6, 0.4 });<br> ListResult(result);</code></td><td class="lg" align="left" valign="bottom" width=43><input type='button' class='button' value='Run' onclick='window.external.RunExample("com.db4odoc.f1.chapter4.CollectionsExample", "retrieveArrays")' /></td></tr></table> <br> <br> <a name="outline178"></a><br><h2>6.2.2. Native Queries</h2><br> 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:<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>public class RetrieveSensorReadoutPredicate : Predicate<br> {<br> public bool Match(SensorReadout candidate)<br> {<br> return Array.IndexOf(candidate.Values, 0.3) > -1<br> && Array.IndexOf(candidate.Values, 0.1) > -1;<br> }<br> }</code></td></tr></table> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// retrieveSensorReadoutNative<br> IObjectSet results = db.Query(new RetrieveSensorReadoutPredicate());<br> ListResult(results);</code></td><td class="lg" align="left" valign="bottom" width=43><input type='button' class='button' value='Run' onclick='window.external.RunExample("com.db4odoc.f1.chapter4.CollectionsExample", "retrieveSensorReadoutNative")' /></td></tr></table> <br> <br> And here's how we find Cars with matching readout values:<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>public class RetrieveCarPredicate : Predicate<br> {<br> public bool Match(Car car)<br> {<br> foreach (SensorReadout sensor in car.History)<br> {<br> if (Array.IndexOf(sensor.Values, 0.3) > -1<br> && Array.IndexOf(sensor.Values, 0.1) > -1)<br> {<br> return true; <br> }<br> }<br> return false;<br> }<br> }</code></td></tr></table> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// retrieveCarNative<br> IObjectSet results = db.Query(new RetrieveCarPredicate());<br> ListResult(results);</code></td><td class="lg" align="left" valign="bottom" width=43><input type='button' class='button' value='Run' onclick='window.external.RunExample("com.db4odoc.f1.chapter4.CollectionsExample", "retrieveCarNative")' /></td></tr></table> <br> <br> <a name="outline179"></a><br><h2>6.2.3. Query API</h2><br> Handling of arrays and collections is analogous to the previous example. First, lets retrieve only the SensorReadouts with specific values:<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// retrieveSensorReadoutQuery<br> IQuery query = db.Query();<br> query.Constrain(typeof(SensorReadout));<br> IQuery valueQuery = query.Descend("_values");<br> valueQuery.Constrain(0.3);<br> valueQuery.Constrain(0.1);<br> IObjectSet results = query.Execute();<br> ListResult(results);</code></td><td class="lg" align="left" valign="bottom" width=43><input type='button' class='button' value='Run' onclick='window.external.RunExample("com.db4odoc.f1.chapter4.CollectionsExample", "retrieveSensorReadoutQuery")' /></td></tr></table> <br> <br> Then let's get some Cars with matching Readout values:<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// retrieveCarQuery<br> IQuery query = db.Query();<br> query.Constrain(typeof(Car));<br> IQuery historyQuery = query.Descend("_history");<br> historyQuery.Constrain(typeof(SensorReadout));<br> IQuery valueQuery = historyQuery.Descend("_values");<br> valueQuery.Constrain(0.3);<br> valueQuery.Constrain(0.1);<br> IObjectSet results = query.Execute();<br> ListResult(results);</code></td><td class="lg" align="left" valign="bottom" width=43><input type='button' class='button' value='Run' onclick='window.external.RunExample("com.db4odoc.f1.chapter4.CollectionsExample", "retrieveCarQuery")' /></td></tr></table> <br> <br> </ul> <a name="outline180"></a><br><h2>6.3. Updating and deleting</h2><br> This should be familiar, we just have to remember to take care of the update depth.<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// updateCar<br> IEmbeddedConfiguration config = Db4oEmbedded.NewConfiguration();<br> config.Common.ObjectClass(typeof(Car)).CascadeOnUpdate(true);<br> using(IObjectContainer db = Db4oEmbedded.OpenFile(config, YapFileName))<br> {<br> IObjectSet result = db.QueryByExample(new Car("BMW", null));<br> Car car = (Car)result.Next();<br> car.Snapshot();<br> db.Store(car);<br> RetrieveAllSensorReadout(db);<br> }</code></td><td class="lg" align="left" valign="bottom" width=43><input type='button' class='button' value='Run' onclick='window.external.RunExample("com.db4odoc.f1.chapter4.CollectionsExample", "updateCar")' /></td></tr></table> <br> <br> There's nothing special about deleting arrays and collections, too.<br> <br> Deleting an object from a collection is an update, too, of course.<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// updateCollection<br> IEmbeddedConfiguration config = Db4oEmbedded.NewConfiguration();<br> config.Common.ObjectClass(typeof(Car)).CascadeOnUpdate(true);<br> using(IObjectContainer db = Db4oEmbedded.OpenFile(config, YapFileName))<br> {<br> IQuery query = db.Query();<br> query.Constrain(typeof (Car));<br> IObjectSet result = query.Descend("_history").Execute();<br> IList history = (IList) result.Next();<br> history.RemoveAt(0);<br> db.Store(history);<br> Car proto = new Car(null, null);<br> result = db.QueryByExample(proto);<br> foreach (Car car in result)<br> {<br> foreach (object readout in car.History)<br> {<br> Console.WriteLine(readout);<br> }<br> }<br> }</code></td><td class="lg" align="left" valign="bottom" width=43><input type='button' class='button' value='Run' onclick='window.external.RunExample("com.db4odoc.f1.chapter4.CollectionsExample", "updateCollection")' /></td></tr></table> <br> <br> (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.)<br> <br> We will delete all cars from the database again to prepare for the next chapter.<br> <br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>// deleteAll<br> IEmbeddedConfiguration config = Db4oEmbedded.NewConfiguration();<br> config.Common.ObjectClass(typeof(Car)).CascadeOnDelete(true);<br> using(IObjectContainer db = Db4oEmbedded.OpenFile(config, YapFileName))<br> {<br> IObjectSet result = db.QueryByExample(new Car(null, null));<br> foreach (object car in result)<br> {<br> db.Delete(car);<br> }<br> IObjectSet readouts = db.QueryByExample(new SensorReadout(null, DateTime.MinValue, null));<br> foreach (object readout in readouts)<br> {<br> db.Delete(readout);<br> }<br> }</code></td><td class="lg" align="left" valign="bottom" width=43><input type='button' class='button' value='Run' onclick='window.external.RunExample("com.db4odoc.f1.chapter4.CollectionsExample", "deleteAll")' /></td></tr></table> <br> <br> <a name="outline181"></a><br><h2>6.4. Conclusion</h2><br> 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 <a href="Inheritance.html#Inheritance">next chapter</a>.<br> <br> <a name="outline182"></a><br><h2>6.5. Full source</h2><br> <table width="100%" cellpadding="3" cellspacing="0" border="0"><tr><td class="lg"> <code>using System;<br> using System.Collections;<br> using System.IO;<br> using Db4objects.Db4o;<br> using Db4objects.Db4o.Config;<br> using Db4objects.Db4o.Query;<br> namespace Db4odoc.Tutorial.F1.Chapter4<br> { <br> public class CollectionsExample : Util<br> {<br> readonly static string YapFileName = Path.Combine(<br> Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),<br> "formula1.yap"); <br> <br> public static void Main(string[] args)<br> {<br> File.Delete(YapFileName);<br> using(IObjectContainer db = Db4oEmbedded.OpenFile(YapFileName))<br> {<br> StoreFirstCar(db);<br> StoreSecondCar(db);<br> RetrieveAllSensorReadout(db);<br> RetrieveSensorReadoutQBE(db);<br> RetrieveCarQBE(db);<br> RetrieveCollections(db);<br> RetrieveArrays(db);<br> RetrieveSensorReadoutQuery(db);<br> RetrieveCarQuery(db);<br> };<br> UpdateCar();<br> UpdateCollection();<br> DeleteAll();<br> using (IObjectContainer db = Db4oEmbedded.OpenFile(YapFileName))<br> {<br> RetrieveAllSensorReadout(db);<br> }<br> }<br> <br> public static void StoreFirstCar(IObjectContainer db)<br> {<br> Car car1 = new Car("Ferrari");<br> Pilot pilot1 = new Pilot("Michael Schumacher", 100);<br> car1.Pilot = pilot1;<br> db.Store(car1);<br> }<br> <br> public static void StoreSecondCar(IObjectContainer db)<br> {<br> Pilot pilot2 = new Pilot("Rubens Barrichello", 99);<br> Car car2 = new Car("BMW");<br> car2.Pilot = pilot2;<br> car2.Snapshot();<br> car2.Snapshot();<br> db.Store(car2); <br> }<br> <br> public static void RetrieveAllSensorReadout(IObjectContainer db)<br> {<br> IObjectSet result = db.QueryByExample(typeof(SensorReadout));<br> ListResult(result);<br> }<br> <br> public static void RetrieveSensorReadoutQBE(IObjectContainer db)<br> {<br> SensorReadout proto = new SensorReadout(new double[] { 0.3, 0.1 }, DateTime.MinValue, null);<br> IObjectSet result = db.QueryByExample(proto);<br> ListResult(result);<br> }<br> <br> public static void RetrieveCarQBE(IObjectContainer db)<br> {<br> SensorReadout protoReadout = new SensorReadout(new double[] { 0.6, 0.2 }, DateTime.MinValue, null);<br> IList protoHistory = new ArrayList();<br> protoHistory.Add(protoReadout);<br> Car protoCar = new Car(null, protoHistory);<br> IObjectSet result = db.QueryByExample(protoCar);<br> ListResult(result);<br> }<br> <br> public static void RetrieveCollections(IObjectContainer db)<br> {<br> IObjectSet result = db.QueryByExample(new ArrayList());<br> ListResult(result);<br> }<br> <br> public static void RetrieveArrays(IObjectContainer db)<br> {<br> IObjectSet result = db.QueryByExample(new double[] { 0.6, 0.4 });<br> ListResult(result);<br> }<br> <br> public static void RetrieveSensorReadoutQuery(IObjectContainer db)<br> {<br> IQuery query = db.Query();<br> query.Constrain(typeof(SensorReadout));<br> IQuery valueQuery = query.Descend("_values");<br> valueQuery.Constrain(0.3);<br> valueQuery.Constrain(0.1);<br> IObjectSet results = query.Execute();<br> ListResult(results);<br> }<br> <br> public static void RetrieveCarQuery(IObjectContainer db)<br> {<br> IQuery query = db.Query();<br> query.Constrain(typeof(Car));<br> IQuery historyQuery = query.Descend("_history");<br> historyQuery.Constrain(typeof(SensorReadout));<br> IQuery valueQuery = historyQuery.Descend("_values");<br> valueQuery.Constrain(0.3);<br> valueQuery.Constrain(0.1);<br> IObjectSet results = query.Execute();<br> ListResult(results);<br> }<br> public class RetrieveSensorReadoutPredicate : Predicate<br> {<br> public bool Match(SensorReadout candidate)<br> {<br> return Array.IndexOf(candidate.Values, 0.3) > -1<br> && Array.IndexOf(candidate.Values, 0.1) > -1;<br> }<br> }<br> <br> public static void RetrieveSensorReadoutNative(IObjectContainer db) <br> {<br> IObjectSet results = db.Query(new RetrieveSensorReadoutPredicate());<br> ListResult(results);<br> }<br> public class RetrieveCarPredicate : Predicate<br> {<br> public bool Match(Car car)<br> {<br> foreach (SensorReadout sensor in car.History)<br> {<br> if (Array.IndexOf(sensor.Values, 0.3) > -1<br> && Array.IndexOf(sensor.Values, 0.1) > -1)<br> {<br> return true; <br> }<br> }<br> return false;<br> }<br> }<br> public static void RetrieveCarNative(IObjectContainer db)<br> {<br> IObjectSet results = db.Query(new RetrieveCarPredicate());<br> ListResult(results);<br> }<br> public static void UpdateCar()<br> {<br> IEmbeddedConfiguration config = Db4oEmbedded.NewConfiguration();<br> config.Common.ObjectClass(typeof(Car)).CascadeOnUpdate(true);<br> using(IObjectContainer db = Db4oEmbedded.OpenFile(config, YapFileName))<br> {<br> IObjectSet result = db.QueryByExample(new Car("BMW", null));<br> Car car = (Car)result.Next();<br> car.Snapshot();<br> db.Store(car);<br> RetrieveAllSensorReadout(db);<br> }<br> }<br> <br> public static void UpdateCollection()<br> {<br> IEmbeddedConfiguration config = Db4oEmbedded.NewConfiguration();<br> config.Common.ObjectClass(typeof(Car)).CascadeOnUpdate(true);<br> using(IObjectContainer db = Db4oEmbedded.OpenFile(config, YapFileName))<br> {<br> IQuery query = db.Query();<br> query.Constrain(typeof (Car));<br> IObjectSet result = query.Descend("_history").Execute();<br> IList history = (IList) result.Next();<br> history.RemoveAt(0);<br> db.Store(history);<br> Car proto = new Car(null, null);<br> result = db.QueryByExample(proto);<br> foreach (Car car in result)<br> {<br> foreach (object readout in car.History)<br> {<br> Console.WriteLine(readout);<br> }<br> }<br> }<br> }<br> <br> public static void DeleteAll()<br> {<br> IEmbeddedConfiguration config = Db4oEmbedded.NewConfiguration();<br> config.Common.ObjectClass(typeof(Car)).CascadeOnDelete(true);<br> using(IObjectContainer db = Db4oEmbedded.OpenFile(config, YapFileName))<br> {<br> IObjectSet result = db.QueryByExample(new Car(null, null));<br> foreach (object car in result)<br> {<br> db.Delete(car);<br> }<br> IObjectSet readouts = db.QueryByExample(new SensorReadout(null, DateTime.MinValue, null));<br> foreach (object readout in readouts)<br> {<br> db.Delete(readout);<br> }<br> }<br> }<br> }<br> }<br> </code></td></tr></table> <br> <br><br><div id="footer"><p align="center">Do you have any questions, suggestions or feedback? Ask your questions in the <a href="http://developer.db4o.com/Forums.aspx" target=_top>db4o forums</a>. Join the <a href="http://developer.db4o.com" target=_top>db4o community</a> for addional resources and news.<br><br><a href="http://www.db4o.com/" target=_top><small>www.db4o.com</small></a></p>.</div><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br></td></tr></table></div></body></html>