Hi,
I want to let you know that during the last few days we have made some enhancements and fixed some bugs / issues related to our LINQ implementation.
Some of them were just annoyances that forced developers to use "not so idiomatic" styles as workarounds, some of them either resulted in crashes or wrong results being returned or even bad performance. Just in case you are curious, here are the tickets to the related issues.
-
COR-1651(bug): LINQ 'Where Not' clause against boolean field throws exception when native query optimization is enabled
- COR-1652 (bug): DateTimeOffset field in ORDER By throws exception
-
COR-1666 (enhancement) : Support method/property chaining on LINQ queries
-
COR-1667 (enhancement) : Support simple method calls on LINQ queries
I'll use the class definition bellow to discuss these issues (Assume we have a bunch of objects of this class stored in the database):
class Person
{
public string Name { get; set; }
public bool IsMale { get; set; }
public Guid Id { get; set; }
public Person Parent { get; set; }
public int GetName()
{
return Name;
}
public Person()
{
Id = Guid.NewGuid();
}
}
The first bug (not operator on simple boolean expressions) only manifests itself in its most basic form:
from Person p in db
where !p.IsMale
select p;
The result was a crash with a InvalidOperationException inside Stack class. The next issue was also related to simple boolean fields without a explicit constraint:
from Person p in db
where p.IsMale // no == true here.
select p;
but instead of throwing an exception this version would silently ignore the where clause effectively querying for all Person class objects as if the following query had been executed:
from Person p in db
select p;
(note the where clause absence)
The good news is that in latest db4o version they work as expected (revision > 13278). If you still needs to use this kind of expressions on previous versions, the workaround is to use the more verbose form:
from Person p in db
where p.IsMale == false // instead of where !p.IsMale
selec p;
and
from Person p in db
where p.IsMale == true // instead of where p.IsMale
select p;
The next two issues were related to our Linq -> Soda translator. In both cases we (wrongly) concluded that the expressions were not convertible to Soda falling back to LINQ for Objects. You would still get the right results but the performance could be seriously affected depending on the actual expression. The following sample shows the failing constructs:
from Person p in db
where p.GetName() == "John Doe"
selet p;
from Perosn p in db
where p.Parent.Name == "John Doe"
select p;
In the first one, GetName() just returns the contents of a property (or a field). The second example just happened to have two indirections (p.Parent.Name). In both cases we used to fail to recognize these patterns as "SODA compliant" and felt back to LINQ for Objects. So, for instance, in the second sample, instead of getting something like:
IQuery q = db.Query();
q.Constrain(typeof(Person));
q.Descend("_parentBackingField").Descend("_nameBackingField").Constrain("John Doe");
foreach(var p in q.Execute())
{
}
we would get something like:
IQuery q = db.Query();
q.Constrain(typeof(Person));
foreach(var p in db.Execute().Where(candidate => candidate.Parent.Name == "John Doe"))
{
}
which is less efficient since all objects of type Person will be retrieved.
The last issue was not directly related to LINQ; instead it was a Soda bug regarding ordering based on value types that implements IComparable / IComparable.
So queries like (note that Id is a Guid, which implements these interfaces):
from Person p in db
orderby p.Id
select p;
would result in an exception like:
Db4objects.Db4o.Internal.IllegalComparisonException: Exception of type 'Db4objects.Db4o.Internal.IllegalComparisonException' was thrown.
at Db4objects.Db4o.Internal.Handlers.StandardReferenceTypeHandler.PrepareComparison(IContext context, Object source)
It was fixed by making StandardReferenceTypeHandler aware of these interfaces.
Well, the good notice (as you already know :) is that all of them were fixed in revision 13278, so if you faced any of these issues you may wish to check it out again :)
As usual, you are invited to download a console application (attached to this post) that accepts a base folder as its argument and runs some tests against all db4o versions found as subdirectories under this base folder.

We can identify all the issues discussed before in the following screen shot (run against version 7.10.96)

And confirm that they were gone on version 7.10.99!
I could not finish this post without saying that three of these issues were reported by community members. To you, our sincere thanks you!
Best.
Adriano