I failed to mention in my previous post that db4o also supports LINQ for executing queries against an object database. In order to avail of this feature, a reference should be added to the Db4objects.Db4o.Linq.dll and you need to specify "using Db4objects.Db4o.Linq;" in your code.
Our previous example made use of a query like this:
Student john = db.Query<Student>(s => s.FirstName.Equals("John")).FirstOrDefault();
Some of you might be asking how performant such a query might be if, for example, there are a million Students in the object database. At first glance, it seems the client will be requesting for all Student objects in the database, and test them one by one if the FirstName property equals the string "John". The db4o engine is actually wiser than that; at runtime it analyses the expression code and converts it internally into SODA (simple object data access) API calls. When this happens, the client does not have to retrieve all Student objects from the database -- the db4o query engine will simply return only the Student objects that has a FirstName property of "John". If you're already familiar with LINQ you might think this is similar to the LINQ approach of converting lambdas into expression trees -- only this time they are converted into SODA calls.
Then again, what if there are ten thousand Student objects in the database with a FirstName of "John"? The return type of the Query<T>() method is IList<T>, not an IEnumerable<T>. This means that all ten thousand matching Student objects will be instantiated into memory as a result of the Query() method, and the FirstOrDefault() extension method will return only the first instance to the reference variable "john" while the 9,999 other instances are discarded. That doesn't sound like a good data access strategy, does it? The solution, in this case, is to make use of LINQ:
Student john = (from Student s in db where s.FirstName.Equals("John") select s).FirstOrDefault();
The expression:
from Student s in db where s.FirstName.Equals("John") select s
is not yet executed; it is simply made into a (db4o-specific) query object by LINQ. When the FirstOrDefault() method is executed, the query is finally executed but only the first result is actually retrieved from the database; the rest of the objects in the potential result set are not instantiated. This, therefore, is the more performant approach.
LINQ to db4o also makes use of SODA query internally by converting the expression trees into them. Not all expressions can be converted into SODA, though. For example, you might have a query like this:
var query = from Student s in db where Encoding.UTF8.GetBytes(s.FirstName).Length > 3 select s;
List<Student> matches = query.ToList();
It wouldn't be able to convert the call to Encoding.UTF8.GetBytes(s.FirstName).Length into an equivalent SODA query. In this case it would have no choice but to instantiate each object into memory from the database, call Encoding.UTF8.GetBytes() on the FirstName property of the Student, then check if the "where" condition in the query is fulfilled. Exercise care whenever you have such complex queries.
Posted
04-24-2009 4:01 PM
by
cruizer