This topic applies to .NET version only
This chapter provides a collection of LINQ examples with db4o, which you can use to find different ways to construct your queries. The information below covers most of the database querying operations and should be enough for the majority of cases. However, it is still advisable to study MSDN resources, which explain in detail how LINQ and Extension methods work. For the introduction to LINQ queries for db4o please refer to LINQ chapter.
Let's fill up the database with some data:
01private static void StoreObjects() 02
{ 03
File.Delete(Db4oFileName); 04
IObjectContainer container = Database(); 05
if (container != null) 06
{ 07
try 08
{ 09
Pilot pilot; 10
Car car; 11
for (int i = 0; i < ObjectCount; i++) 12
{ 13
pilot = new Pilot("Test Pilot #" + i, i + 10); 14
car = new Car("Test model #" + i, pilot); 15
container.Store(car); 16
} 17
container.Commit(); 18
} 19
catch (Db4oException ex) 20
{ 21
System.Console.WriteLine("Db4o Exception: " + ex.Message); 22
} 23
catch (Exception ex) 24
{ 25
System.Console.WriteLine("System Exception: " + ex.Message); 26
} 27
finally 28
{ 29
CloseDatabase(); 30
} 31
} 32
}
01Private Shared Sub StoreObjects() 02
File.Delete(Db4oFileName) 03
Dim container As IObjectContainer = Database() 04
If container IsNot Nothing Then 05
Try 06
Dim pilot As Pilot 07
Dim car As Car 08
For i As Integer = 0 To ObjectCount - 1 09
pilot = New Pilot("Test Pilot #" + i.ToString(), i + 10) 10
car = New Car("Test model #" + i.ToString(), pilot) 11
container.Store(car) 12
Next 13
container.Commit() 14
Catch ex As Db4oException 15
System.Console.WriteLine("Db4o Exception: " + ex.Message) 16
Catch ex As Exception 17
System.Console.WriteLine("System Exception: " + ex.Message) 18
Finally 19
CloseDatabase() 20
End Try 21
End If 22
End Sub
In order to select objects of only Pilot class we can issue the following query:
01private static void SelectPilotByNameAndPoints() 02
{ 03
IObjectContainer container = Database(); 04
if (container != null) 05
{ 06
try 07
{ 08
IEnumerable<Pilot> result = from Pilot p in container 09
where p.Name.StartsWith("Test") && p.Points > 12 10
select p; 11
12
ListResult(result); 13
} 14
catch (Exception ex) 15
{ 16
System.Console.WriteLine("System Exception: " + ex.Message); 17
} 18
finally 19
{ 20
CloseDatabase(); 21
} 22
} 23
}
01Private Shared Sub SelectPilotByNameAndPoints() 02
Dim container As IObjectContainer = Database() 03
If container IsNot Nothing Then 04
Try 05
Dim result As IEnumerable(Of Pilot) = From p As Pilot In container _ 06
Where p.Name.StartsWith("Test") And p.Points > 12 _ 07
Select p 08
09
ListResult(result) 10
catch ex As Exception 11
System.Console.WriteLine("System Exception: " + ex.Message) 12
finally 13
CloseDatabase() 14
End Try 15
End If 16
End Sub
Note, that where clause is optional: if it is not specified all objects of Pilot class will be returned.
We can make querying even easier by using anonymous types:
01private static void SelectByNameAndPoints() 02
{ 03
IObjectContainer container = Database(); 04
if (container != null) 05
{ 06
try 07
{ 08
var result = from Pilot p in container 09
where p.Name.StartsWith("Test") && p.Points > 12 10
select p; 11
12
ListResult(result); 13
} 14
catch (Exception ex) 15
{ 16
System.Console.WriteLine("System Exception: " + ex.Message); 17
} 18
finally 19
{ 20
CloseDatabase(); 21
} 22
} 23
}
01Private Shared Sub SelectByNameAndPoints() 02
Dim container As IObjectContainer = Database() 03
If container IsNot Nothing Then 04
Try 05
Dim result = From p As Pilot In container _ 06
Where p.Name.StartsWith("Test") And p.Points > 12 _ 07
Select p 08
ListResult(result) 09
catch ex As Exception 10
System.Console.WriteLine("System Exception: " + ex.Message) 11
finally 12
CloseDatabase() 13
End Try 14
End If 15
End Sub
You can easily use LINQ to create database objects clones:
01private static void SelectClone() 02
{ 03
IObjectContainer container = Database(); 04
if (container != null) 05
{ 06
try 07
{ 08
var result = from Pilot p in container 09
where p.Name.StartsWith("Test") && p.Points > 12 10
select new Pilot(p.Name, p.Points); 11
12
ListResult(result); 13
} 14
catch (Exception ex) 15
{ 16
System.Console.WriteLine("System Exception: " + ex.Message); 17
} 18
finally 19
{ 20
CloseDatabase(); 21
} 22
} 23
}
01Private Shared Sub SelectClone() 02
Dim container As IObjectContainer = Database() 03
If container IsNot Nothing Then 04
Try 05
Dim result = From p As Pilot In container _ 06
Where p.Name.StartsWith("Test") And p.Points > 12 _ 07
Select New Pilot(p.Name, p.Points) 08
ListResult(result) 09
Catch ex As Exception 10
System.Console.WriteLine("System Exception: " + ex.Message) 11
Finally 12
CloseDatabase() 13
End Try 14
End If 15
End Sub
Retrieved objects are not bound to the object container, but they duplicate the values from the database. You can use them for an "object-readonly" mode.
With the selection we are not bound to only one type of objects - actually we can select everything that is currently in the database:
01private static void SelectEverythingByName() 02
{ 03
IObjectContainer container = Database(); 04
if (container != null) 05
{ 06
try 07
{ 08
var result = from object o in container 09
where o.ToString().StartsWith("Test") 10
select o; 11
ListResult(result); 12
} 13
catch (Exception ex) 14
{ 15
System.Console.WriteLine("System Exception: " + ex.Message); 16
} 17
finally 18
{ 19
CloseDatabase(); 20
} 21
} 22
}
01Private Shared Sub SelectEverythingByName() 02
Dim container As IObjectContainer = Database() 03
If container IsNot Nothing Then 04
Try 05
Dim result = From o As Object In container _ 06
Select res = o _ 07
Where res.ToString().StartsWith("Test") 08
ListResult(result) 09
Catch ex As Exception 10
System.Console.WriteLine("System Exception: " + ex.Message) 11
finally 12
CloseDatabase() 13
End Try 14
End If 15
End Sub
We can further use this broad selection too. As the query result implements IQueryable interface, we can re-use it to retrieve more specific objects:
01private static void SelectFromSelection() 02
{ 03
IObjectContainer container = Database(); 04
if (container != null) 05
{ 06
try 07
{ 08
var allObjects = from object o in container select o; 09
var listObjects = allObjects.ToList(); 10
var pilots = from object p in listObjects 11
where p.GetType().FullName.Equals("Db4objects.Db4odoc.LinqCollection.Pilot") 12
&& ((Pilot)p).Points > 25 13
select (Pilot)p; 14
ListResult(pilots); 15
var cars = from object car in allObjects 16
where car.GetType().FullName.Equals("Db4objects.Db4odoc.LinqCollection.Car") 17
&& pilots.Contains(((Car)car).Pilot) 18
select (Car)car; 19
ListResult(cars); 20
} 21
catch (Exception ex) 22
{ 23
System.Console.WriteLine("System Exception: " + ex.Message); 24
} 25
finally 26
{ 27
CloseDatabase(); 28
} 29
} 30
}
01Private Shared Sub SelectFromSelection() 02
Dim container As IObjectContainer = Database() 03
If container IsNot Nothing Then 04
Try 05
Dim allObjects = From o As Object In container Select o 06
Dim listOfObjects = allObjects.ToList() 07
Dim pilots = From p As Object In allObjects _ 08
Where (p.GetType().FullName.Equals("Linq.Db4objects.Db4odoc.Linq.Pilot")) _ 09
Select pilot1 = CType(p, Pilot) Where pilot1.Points > 25 10
ListResult(pilots) 11
Dim cars = From car As Object In allObjects _ 12
Where car.GetType().FullName.Equals("Linq.Db4objects.Db4odoc.Linq.Car") _ 13
Select car1 = CType(car, Car) _ 14
Where pilots.Contains(CType(car1, Car).Pilot) 15
ListResult(cars) 16
Catch ex As Exception 17
System.Console.WriteLine("System Exception: " + ex.Message) 18
finally 19
CloseDatabase() 20
End Try 21
End If 22
End Sub
In this example we use an all objects selection to find a range of pilots and then cars with pilots within the range. Remember, however, that the objects in allObjects variable are not actually retrieved from the database until they are browsed or used. If you want to get them all into the memory for future use, utilize ToList or ToArray methods.
Above we've already discussed how to select objects of one type based on the selection of the other type. However, that way is rather cumbersome and most probably you won't need it: you can use join operator instead:
01private static void SelectJoin() 02
{ 03
IObjectContainer container = Database(); 04
if (container != null) 05
{ 06
try 07
{ 08
var result = from Pilot p in container 09
from Car c in container 10
where p.Points > 25 11
&& c.Pilot.Equals(p) 12
select c; 13
14
ListResult(result); 15
} 16
catch (Exception ex) 17
{ 18
System.Console.WriteLine("System Exception: " + ex.Message); 19
} 20
finally 21
{ 22
CloseDatabase(); 23
} 24
} 25
}
01Private Shared Sub SelectJoin() 02
Dim container As IObjectContainer = Database() 03
If container IsNot Nothing Then 04
Try 05
Dim result = From p As Pilot In container _ 06
From c As Car In container _ 07
Where (p.Points > 25) _ 08
And c.Pilot.Equals(p) _ 09
Select c 10
ListResult(result) 11
Catch ex As Exception 12
System.Console.WriteLine("System Exception: " + ex.Message) 13
Finally 14
CloseDatabase() 15
End Try 16
End If 17
End Sub
This simple syntax allows you to join any amount of classes using any possible relationship between them. You can also make use of Join extension method syntax to get the same result.
Sorting is added with orderby
operator and can
be ascending(default) or descending.
01private static void SelectOrdered() 02
{ 03
IObjectContainer container = Database(); 04
if (container != null) 05
{ 06
try 07
{ 08
var result = from Pilot p in container 09
where p.Points < 15 10
orderby p.Name descending 11
select p; 12
13
ListResult(result); 14
} 15
catch (Exception ex) 16
{ 17
System.Console.WriteLine("System Exception: " + ex.Message); 18
} 19
finally 20
{ 21
CloseDatabase(); 22
} 23
} 24
}
01Private Shared Sub SelectOrdered() 02
Dim container As IObjectContainer = Database() 03
If container IsNot Nothing Then 04
Try 05
Dim result = From p As Pilot In container _ 06
Where (p.Points < 15) Order By p.Name Descending Select p 07
ListResult(result) 08
Catch ex As Exception 09
System.Console.WriteLine("System Exception: " + ex.Message) 10
Finally 11
CloseDatabase() 12
End Try 13
End If 14
End Sub
We can also use subsequent sorts. For example sort by name descending and by points ascending:
01private static void StoreForSorting() 02
{ 03
File.Delete(Db4oFileName); 04
IObjectContainer container = Database(); 05
if (container != null) 06
{ 07
try 08
{ 09
Pilot pilot; 10
for (int i = 0; i < ObjectCount; i++) 11
{ 12
pilot = new Pilot("Test Pilot #" + i, i); 13
container.Store(pilot); 14
} 15
for (int i = 0; i < ObjectCount; i++) 16
{ 17
pilot = new Pilot("Test Pilot #" + i, (i + 10)); 18
container.Store(pilot); 19
} 20
container.Commit(); 21
} 22
catch (Db4oException ex) 23
{ 24
System.Console.WriteLine("Db4o Exception: " + ex.Message); 25
} 26
catch (Exception ex) 27
{ 28
System.Console.WriteLine("System Exception: " + ex.Message); 29
} 30
finally 31
{ 32
CloseDatabase(); 33
} 34
} 35
}
01private static void SelectComplexOrdered() 02
{ 03
IObjectContainer container = Database(); 04
if (container != null) 05
{ 06
try 07
{ 08
var result = from Pilot p in container 09
orderby p.Name descending, 10
p.Points ascending 11
select p; 12
13
ListResult(result); 14
} 15
catch (Exception ex) 16
{ 17
System.Console.WriteLine("System Exception: " + ex.Message); 18
} 19
finally 20
{ 21
CloseDatabase(); 22
} 23
} 24
}
01Private Shared Sub StoreForSorting() 02
03
File.Delete(Db4oFileName) 04
Dim container As IObjectContainer = Database() 05
If container IsNot Nothing Then 06
Try 07
Dim p As Pilot 08
For i As Integer = 0 To ObjectCount - 1 09
p = New Pilot("Test Pilot #" + i.ToString(), i) 10
container.Store(p) 11
Next 12
For i As Integer = 0 To ObjectCount - 1 13
p = New Pilot("Test Pilot #" + i.ToString(), (i + 10)) 14
container.Store(p) 15
Next 16
container.Commit() 17
Catch ex As Db4oException 18
System.Console.WriteLine("Db4o Exception: " + ex.Message) 19
Catch ex As Exception 20
System.Console.WriteLine("System Exception: " + ex.Message) 21
Finally 22
CloseDatabase() 23
End Try 24
End If 25
End Sub
01Private Shared Sub SelectComplexOrdered() 02
Dim container As IObjectContainer = Database() 03
If container IsNot Nothing Then 04
Try 05
Dim result = From p As Pilot In container _ 06
Order By p.Name Descending Order By p.Points Ascending _ 07
Select p 08
ListResult(result) 09
catch ex As Exception 10
System.Console.WriteLine("System Exception: " + ex.Message) 11
finally 12
CloseDatabase() 13
End Try 14
End If 15
End Sub
The same effect can be achieved by using
OrderBy/OrderByDescending
and ThenBy/ThenByDescending
extension methods.
Grouping results can be often useful in different reports. For example, we can group the data from the previous example by pilot's name:
01private static void SelectGroupByName() 02
{ 03
IObjectContainer container = Database(); 04
if (container != null) 05
{ 06
try 07
{ 08
var result = (from Pilot p in container 09
orderby p.Points descending 10
select p).GroupBy(value => value.Points, value => new {value.Name, value.Points}); 11
foreach (var group in result) 12
{ 13
Console.WriteLine("Pilots with {0} points:", group.Key); 14
15
foreach (var tuple in group) 16
Console.WriteLine(" {0}", tuple); 17
} 18
} 19
catch (Exception ex) 20
{ 21
System.Console.WriteLine("System Exception: " + ex.Message); 22
} 23
finally 24
{ 25
CloseDatabase(); 26
} 27
} 28
}
01Private Shared Sub SelectGroupByName() 02
Dim container As IObjectContainer = Database() 03
If container IsNot Nothing Then 04
Try 05
Dim result = From p As Pilot In container _ 06
Order By p.Points Descending _ 07
Select p Group By p.Points, p.Name Into Group Select Name, Points 08
For Each value In result 09
Console.WriteLine(" {0}", value) 10
Next 11
Catch ex As Exception 12
System.Console.WriteLine("System Exception: " + ex.Message) 13
Finally 14
CloseDatabase() 15
End Try 16
End If 17
End Sub
Here we use GroupBy
extension method. The
parameters specify the grouping property (Points) and the display property
(Name).
Sometimes we need to apply some calculation on each result - with LINQ we can do that directly in the query:
01private static void SelectWithModifiedResult() 02
{ 03
IObjectContainer container = Database(); 04
int maxPoints = 100; 05
if (container != null) 06
{ 07
try 08
{ 09
/*Select percentage*/ 10
var result = from Pilot p in container 11
where p.Name.StartsWith("Test") 12
select String.Format("{0}: {1}%", p.Name, (p.Points * 100 / maxPoints)); 13
14
ListResult(result); 15
} 16
catch (Exception ex) 17
{ 18
System.Console.WriteLine("System Exception: " + ex.Message); 19
} 20
finally 21
{ 22
CloseDatabase(); 23
} 24
} 25
}
01Private Shared Sub SelectWithModifiedResult() 02
Dim container As IObjectContainer = Database() 03
Dim maxPoints As Integer = 100 04
If container IsNot Nothing Then 05
Try 06
' Select percentage 07
Dim result = From p As Pilot In container _ 08
Where (p.Name.StartsWith("Test")) _ 09
Select String.Format("{0}: {1}%", p.Name, (p.Points * 100 / maxPoints)) 10
ListResult(result) 11
catch ex As Exception 12
System.Console.WriteLine("System Exception: " + ex.Message) 13
finally 14
CloseDatabase() 15
End Try 16
End If 17
End Sub
In the example above the query will bring as the calculated
percentage of maximum for each pilot's points.
Though a query usually returns all the candidates matching
the selected criteria, we can specify which of the results we want:
First
, ElementAt
, Any
, All
.
01private static void SelectAny() 02
{ 03
IObjectContainer container = Database(); 04
if (container != null) 05
{ 06
try 07
{ 08
/*Checks if query returns any results*/ 09
var result = (from Pilot p in container 10
where p.Name.EndsWith("Test") 11
select p).Any(); 12
13
System.Console.WriteLine("The query returns any results: " + result); 14
} 15
catch (Exception ex) 16
{ 17
System.Console.WriteLine("System Exception: " + ex.Message); 18
} 19
finally 20
{ 21
CloseDatabase(); 22
} 23
} 24
}
01Private Shared Sub SelectAny() 02
Dim container As IObjectContainer = Database() 03
If container IsNot Nothing Then 04
Try 05
'Checks if query returns any results 06
Dim result = Aggregate p As Pilot In container _ 07
Where p.Name.EndsWith("Test") Into Any() 08
System.Console.WriteLine("The query returns any results: " + result.ToString()) 09
Catch ex As Exception 10
System.Console.WriteLine("System Exception: " + ex.Message) 11
Finally 12
CloseDatabase() 13
End Try 14
End If 15
End Sub
The query above will return true
if there are
any objects in the result set and false
otherwise.
Often we are not interested in each and every result, but need some statistics about it: sum, aggregate, average, max etc. This can be achieved with extension methods.
01private static void SelectAverage() 02
{ 03
IObjectContainer container = Database(); 04
if (container != null) 05
{ 06
try 07
{ 08
/*Find the average of pilot points*/ 09
var result = (from Pilot p in container 10
where p.Name.StartsWith("Test") 11
select p.Points).Average(); 12
13
System.Console.WriteLine(result); 14
} 15
catch (Exception ex) 16
{ 17
System.Console.WriteLine("System Exception: " + ex.Message); 18
} 19
finally 20
{ 21
CloseDatabase(); 22
} 23
} 24
}
01Private Shared Sub SelectAverage() 02
Dim container As IObjectContainer = Database() 03
If container IsNot Nothing Then 04
Try 05
'Find the average of pilot points 06
Dim result = Aggregate p As Pilot In container _ 07
Where p.Name.StartsWith("Test") Into Average(p.Points) 08
System.Console.WriteLine(result) 09
Catch ex As Exception 10
System.Console.WriteLine("System Exception: " + ex.Message) 11
Finally 12
CloseDatabase() 13
End Try 14
End If 15
End Sub
This method returns only the average value of pilot points.
01private static void SelectAggregate() 02
{ 03
IObjectContainer container = Database(); 04
if (container != null) 05
{ 06
try 07
{ 08
/*Select pilot names separated by semicolon*/ 09
var result = (from Pilot p in container 10
where p.Name.StartsWith("Test") 11
select p.Name).Aggregate(new StringBuilder(), 12
(acc, value) => acc.AppendFormat("{0}; ", value)); 13
14
System.Console.WriteLine(result); 15
} 16
catch (Exception ex) 17
{ 18
System.Console.WriteLine("System Exception: " + ex.Message); 19
} 20
finally 21
{ 22
CloseDatabase(); 23
} 24
} 25
}
01Private Shared Sub SelectAggregate() 02
Dim container As IObjectContainer = Database() 03
If container IsNot Nothing Then 04
Try 05
' Select pilot names separated by semicolon 06
Dim result = From p As Pilot In container _ 07
Where p.Name.StartsWith("Test") Select p.Name 08
Dim sumString As String = result.Aggregate("", Function(acc, value) acc + ";" + value) 09
10
System.Console.WriteLine(sumString) 11
12
Catch ex As Exception 13
System.Console.WriteLine("System Exception: " + ex.Message) 14
Finally 15
CloseDatabase() 16
End Try 17
End If 18
End Sub
In this case we use Aggregate
extension method
to return all the names and a semicolon-separated string. In
Aggregate
function first parameter specify the initial return
value, second parameter is a function that appends each new value to the
initial value.