Introduction
In my previous post I described how to deal with complex types and many to one dependencies now I will do the one to many relationships.
For this I will add a collection to our Person.
Public Class Person
Public Property LastName As String
Public Property FirstName As String
Public Property Address As Address
Public Property BadHabits As IList(Of BadHabit)
End Class
Public Class Address
Public Property Street As String
Public Property HouseNumber As String
End Class
Public Class BadHabit
Public Property BadHabit As String
End Class```
## one to many
For this we first have to add a table to our database.
```vbnet
Private Sub CreateTableBadHabits()
Using cn = New SqlCeConnection(ConnectionString)
If cn.State = ConnectionState.Closed Then
cn.Open()
End If
Dim sql = "create table BadHabit (Id int IDENTITY(1,1) PRIMARY KEY, BadHabit nvarchar (40) not null, PersonId int)"
Using cmd = New SqlCeCommand(sql, cn)
cmd.ExecuteNonQuery()
End Using
sql = "ALTER TABLE BadHabit ADD CONSTRAINT FK_BadHabit_Person FOREIGN KEY (PersonId) REFERENCES Person(Id)"
Using cmd = New SqlCeCommand(sql, cn)
cmd.ExecuteNonQuery()
End Using
End Using
End Sub```
We will better normalize it later when we have some time ;-). As you can see I also added the foreign key. I will leave the index creation up to you.
And we also need some more testdata.
```vbnet
db.Address.Insert(New With {.Street = "street1", .HouseNumber = "1"})
db.Person.Insert(New With {.LastName = "lastname1", .FirstName = "firstname1", .AddressId = 1})
db.Person.Insert(New With {.LastName = "lastname1", .FirstName = "firstname2", .AddressId = 1})
db.BadHabit.Insert(New With {.BadHabit = "Drinks", .PersonId = 1})
db.BadHabit.Insert(New With {.BadHabit = "Smokes", .PersonId = 1})
db.BadHabit.Insert(New With {.BadHabit = "Eats to much", .PersonId = 2})
```
And now for the querying.
```vbnet
Dim result = db.Persons.FindAllByLastName("lastname1").WithAddress
For Each person In result
Console.WriteLine("{0} {1} {2} {3} {4}", person.Id, person.LastName, person.FirstName, person.Address.Street, person.Address.HouseNumber)
For Each badHabit In person.BadHabits
Console.WriteLine(badHabit.BadHabit)
Next
Next```
Dude, that’s simple… I guess that’s why they call it Simple.Data and not PetaPoco 😉
Of course the above still lazy loads and gives this SQL.
```tsql
Simple.Data.Ado:
Text
select [Person].[Id],[Person].[LastName],[Person].[FirstName],[Person].[AddressId],[Address].[Id] AS [__with1__Address__Id],[Address].[Street] AS [__with1__Address__Street],[Address].[HouseNumber] AS [__with1__Address__HouseNumber] from [Person] LEFT JOIN [Address] ON ([Address].[Id] = [Person].[AddressId]) WHERE [Person].[LastName] = @p1
@p1 (String) = lastname1
Simple.Data.Ado:
Text
select [BadHabit].[Id],[BadHabit].[BadHabit],[BadHabit].[PersonId] from [BadHabit] WHERE [BadHabit].[PersonId] = @p1
@p1 (Int32) = 1
Simple.Data.Ado:
Text
select [BadHabit].[Id],[BadHabit].[BadHabit],[BadHabit].[PersonId] from [BadHabit] WHERE [BadHabit].[PersonId] = @p1
@p1 (Int32) = 2```
That again is not always a desired behaviour and in our case we just want to eagerly fetch our data. Which of course is stupidly simple to do just by adding the WithStatement like this.
```vbnet
Dim result = db.Persons.FindAllByLastName("lastname1").WithAddress.WithBadHabits
For Each person In result
Console.WriteLine("{0} {1} {2} {3} {4}", person.Id, person.LastName, person.FirstName, person.Address.Street, person.Address.HouseNumber)
For Each BadHabit In person.BadHabits
Console.WriteLine(BadHabit.BadHabit)
Next
Next```
And now I get this sql instead.
```vbnet
Simple.Data.Ado:
Text
select [Person].[Id],[Person].[LastName],[Person].[FirstName],[Person].[AddressId],[Address].[Id] AS [__with1__Address__Id],[Address].[Street] AS [__with1__Address__Street],[Address].[HouseNumber] AS [__with1__Address__HouseNumber],[BadHabit].[Id] AS [__withn__BadHabits__Id],[BadHabit].[BadHabit] AS [__withn__BadHabits__BadHabit],[BadHabit].[PersonId] AS [__withn__BadHabits__PersonId] from [Person] LEFT JOIN [Address] ON ([Address].[Id] = [Person].[AddressId]) LEFT JOIN [BadHabit] ON ([Person].[Id] = [BadHabit].[PersonId]) WHERE [Person].[LastName] = @p1
@p1 (String) = lastname1```
And that’s a lot better.
You can however not do this.
```vbnet
person.BadHabits(0).BadHabit```
Because that will give you this error.
> No default member found for type ‘SimpleQuery’.
I think that is because BadHabits is of type SimpleQuery and the default for SimpleQuery is an IEnumerator. But you can do this instead.
```vbnet
person.BadHabits.ToList()(0).BadHabit```
## Conclusion
What can I say. It’s simple.