Search code examples
vb.netentity-frameworklinq-to-entities

Custom function(s) in LINQ to Entities? How to write acceptable code?


Use of my simple function causes app to exit all the nested Using blocks and returns control to very outer End Using statement. But built-in function works fine. How to bypass this strange situation?

Public Shared ReadOnly GlobalSettingsKeyList As New HashSet(Of String)

Public Shared Function IsGlobalSetting(key As String) As Boolean
    Return GlobalSettingsKeyList.Contains(key)
End Function

What doesn't work:

Using db = powerEntities.Open()
    dim userID = 1
    dim dbSettingsFound = (From setting In db.SETTINGS
                           Where setting.idUsers = If(IsGlobalSetting(setting.Name), Nothing, userID)
                           Where setting.Name.Contains(keyToMatch)) _
                        .ToDictionary(Function(x) x.Name, Function(y) y.Value)
End Using

What works fine:

Using db = powerEntities.Open()
    dim userID = 1
    dim dbSettingsFound = (From setting In db.SETTINGS
                           Where setting.idUsers = If(GlobalSettingsKeyList.Contains(setting.Name), Nothing, userID)
                           Where setting.Name.Contains(keyToMatch)) _
                        .ToDictionary(Function(x) x.Name, Function(y) y.Value)
End Using

{"LINQ to Entities does not recognize the method 'Boolean IsGlobalSetting(System.String)' method, and this method cannot be translated into a store expression."}


Solution

  • Done! Thanks to Jarekczek's answer here and his LinqExprHelper

    So there is a way!

    Private Shared Function GetDefaultKey(key As String) As String
            If key.Contains("Station") Then
                Return $"default{key.Substring("Station")}" 'my String Extension
            Else
                Return $"default{key}"
            End If
    End Function
    
    Public Shared Function GetDefaultKeyAndCompareSetting(ByVal key As String) As Expression(Of Func(Of Settings, Boolean))
            key = GetDefaultKey(key)
            Return LinqExprHelper.NewExpr(Function(u As Settings) u.Name.Equals(key))
    End Function
    

    used like this...

    Shared Sub Example(key As String)
    ...
        Dim masterExpr = LinqExprHelper.NewExpr(Function(u As Settings, ByVal formatCompare As String) (formatCompare))
        Dim isSameAsDefKey = masterExpr.ReplacePar("formatCompare", GetDefaultKeyAndCompareSetting(key).Body)
    
        Dim result = (From def In db.Settings
                      Where def.idUsers Is Nothing).
                      Where(CType(isSameAsDefKey, Expression(Of Func(Of Settings, Boolean)))).FirstOrDefault
    ...
    End Sub
    

    ...works like a charm