Using the GLOB function in LINQ to Entities

江枫思渺然 提交于 2019-12-02 03:27:33

问题


I need SQLite's glob function in a (C#) method which has to return Expression<Func<RandomEntity, bool>> -- and I need glob because only then the index is used (already checked using EXPLAIN QUERY PLAN [..]).

So I added the following function mapping to <edmx:StorageModels><Schema> (SSDL):

    <Function Name="glob" Aggregate="false" BuiltIn="true" NiladicFunction="false" IsComposable="true" ReturnType="bit">
        <Parameter Name="pattern" Mode="In" Type="nvarchar"/>
        <Parameter Name="target" Mode="In" Type="nvarchar"/>
    </Function>

and a C# stub method:

public static class SQLiteFunctions
{
    [DbFunction("Model.Store", "glob")]
    public static bool Glob(string pattern, string target)
    {
        throw new NotImplementedException("Only exists for IQueryable/Expression<Func<T,bool>>!");
    }
}

and the usage (just a sample producing tiny SQL):

var count = context.Users.Count(u => SQLiteFunctions.Glob("admin*", u.Name));

While this works the resulting SQL uses a "silly" = 1 comparison since the model only knows the datatype "bit" (which is 0 or 1) and I found no real boolean type although the native glob function seems to be true boolean:

SELECT 
[GroupBy1].[A1] AS [C1]
FROM ( SELECT 
    Count([Filter1].[A1]) AS [A1]
    FROM ( SELECT 
        1 AS [A1]
        FROM [Users] AS [Extent1]
        WHERE (glob('admin*', [Extent1].[Name])) = 1
    )  AS [Filter1]
)  AS [GroupBy1]

The problem: This way (with "= 1") SQLite doesn't use the index and the query is badly slow. If I remove the 3 characters "= 1" the query becomes fast and also the query plan changes from "SCAN TABLE" to "SEARCH TABLE USING INDEX".

Any ideas how to make the function a true boolean function?


Addition:

I also tried using the CSDL section ():

    <Function Name="GlobMatch" ReturnType="Edm.Boolean">
        <Parameter Name="globPattern" Type="Edm.String" />
        <Parameter Name="target" Type="Edm.String" />
        <DefiningExpression> glob(globPattern, target) </DefiningExpression>
    </Function>

and

    [DbFunction("DoPiMo", "GlobMatch")]
    public static bool Glob2(string globPattern, string target)
    {
        throw new NotImplementedException("Only exists for IQueryable/Expression<Func<T,bool>>!");
    }

but this only produces a runtime error saying "glob" is not defined/known.


回答1:


When doing a prefix search with LIKE or GLOB, SQLite rewrites it as two comparisons.

You could just write the two comparisons directly:

u.Name >= "admin" and u.Name < "admio"


来源:https://stackoverflow.com/questions/24043080/using-the-glob-function-in-linq-to-entities

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!