Skip to content

Why can't I use my function in a database query

Zev Spitz edited this page Aug 19, 2020 · 2 revisions

Anyone using EF or some other ORM to query a database inevitably runs into this problem (or some variant of it).

The Problem

Let's say I have a Person class:

Class Person
    Property Id As Integer
    Property LastName As String
    Property FirstName As String
    Property DateOfBirth As Date
End Class

and I want to write a query against the database, using a DB context, which returns all the people whose last name starts with "A":

Class MyDbContext
    Inherits DbContext
    Property Persons As DbSet(Of Person)
    Protected Overrides Sub OnConfiguring(optionsBuilder As DbContextOptionsBuilder)
        optionsBuilder.UseSqlite("DataSource=People.db")
    End Sub
End Class

Dim ctx = New MyDbContext
Dim qry =
    From person In ctx.Person
    Where person.LastName.StartsWith("A")
    Select person

For Each person In qry
    Dim output = $"LastName: {person.LastName}, FirstName: {person.FirstName}, DateOfBirth: {person.DateOfBirth}"
    Console.WriteLine(output)
Next

Everything works fine.

But now, I want to write a query that returns all the peeople whose year of birth ends with "9" -- 2019, 2009, 1999 etc. There is no EndsWith method on Date, or even on Integer which is the type returned from the Date.Year property.

However, there is an EndsWith method on String. The simplest method of converting an Integer to String is by calling the ToString method.

Dim ctx1 = New MyDbContext
Dim qry1 =
    From person In ctx.Person
    Where person.DateOfBirth.Year.ToString.EndsWith("9")
    Select person

For Each person In qry1
    Dim output = $"LastName: {person.LastName}, FirstName: {person.FirstName}, DateOfBirth: {person.DateOfBirth}"
    Console.WriteLine(output)
Next

But this code fails, with some error about

TODO -- error

Even stranger, if I run what appears to be the exact same code against a List(Of Person):

Dim lst = New List(Of Person)

' fill list here

Dim qry1 =
    From person In lst
    Where person.DateOfBirth.Year.ToString.EndsWith("9")
    Select person

For Each person In qry1
    Dim output = $"LastName: {person.LastName}, FirstName: {person.FirstName}, DateOfBirth: {person.DateOfBirth}"
    Console.WriteLine(output)
Next

The code doesn't choke on .ToString, and runs without errors.


LINQ queries desugar to LINQ operator methods

question -- how does SQL Server understand StartsWith, EndsWith