将“option(maxrecursion 0)”与EntityFramework EntitySql一起使用

本文关键字:EntityFramework EntitySql 一起 option maxrecursion | 更新日期: 2023-09-27 18:33:26

我有一个 SqlServer 函数,它根据输入(一个带有 id 的 csv 字符串)使用 cte 执行重新选择。

不幸的是,我不能在我的函数中使用"选项(maxrecursion 0)",必须在执行函数时使用它。问题是我找不到如何将此选项与EntityFramework的EntitySql一起使用。

考虑到我的函数被称为MyRecursiveFunction,这里有一些代码片段:

public virtual IQueryable<MyFunctionReturnType> ExecuteMyFunction(IObjectContextAdapter objContextAdapter, string csvIds)
{
    var idsParam = new ObjectParameter("idsParam", csvIds);
    // This is the original one, that works, but has no "option(maxrecursion 0)"
    return objContextAdapter.CreateQuery<MyFunctionReturnType>("[MyRecursiveFunction](@idsParam)", idsParam);
    // gives me an error of incorrect syntax near "option"
    return objContextAdapter.CreateQuery<MyFunctionReturnType>("select VALUE tblAlias from [MyRecursiveFunction](@idsParam) as tblAlias OPTION(MAXRECURSION 0)", idsParam);
    // Also gives me syntax error:
    return objContextAdapter.CreateQuery<MyFunctionReturnType>("MyRecursiveFunction(@idsParam) option(maxrecursion 0)", idsParam);
}

有人知道如何将option(maxrecursion 0)与实体SQL一起使用吗?

我知道我可以使用"ExecuteStoreQuery"来执行我想要的任何sql查询,但我确实需要一个IQueryable,因为"ExecuteMyFunction"的返回将在实现之前与另一个IQueryable连接

请节省您的时间,不要建议ExecuteStoreQueryAsQueryable一起打电话....我真的不想具体化整个结果集,因为我只会具体化 10 个分页结果

这是我的TVF的表示:

-- Consider that I have the given table for executing this function.
-- This table has a foreign key to itself, as the data represents a tree, like an organization chart
CREATE TABLE MyTable
(
    Id INT,
    ParentId INT, -- FK to 'MyTable'.'Id',
    Name VARCHAR(400)
)
-- Here is my function definition:
CREATE FUNCTION MyRecursiveFunction (@idsParam VARCHAR(MAX))
RETURNS TABLE
AS
RETURN
(
    -- create a cte for recursively getting the data
    with myCte (id, parentId) as
    (
        SELECT tbl.Id, tbl.ParentId FROM MyTable AS tbl
        -- This function just transform the varchar into a table of "Value"
        INNER JOIN [dbo].[SplitTextIntoTableOfInt](@idsParam, ',') AS ids ON a.ParentId = ids.Value
        UNION ALL
        SELECT a.Id, a.ParentId FROM myCte AS parent
        INNER JOIN MyTable tbl ON tbl.ParentId = parent.Id
    )
    SELECT * FROM myCte -- I can't use 'option(maxrecursion 0)' in here
)

将“option(maxrecursion 0)”与EntityFramework EntitySql一起使用

唯一可以做的是使用 EF 拦截,并在运行之前将该选项添加到 EF 生成的 SQL 中。

为此,您需要实现 IDbCommandInterceptor 接口,并使用 DbInterception.Add(new YousCommandInterceptor()); 注册侦听器。

侦听器可以在将查询发送到服务器之前添加该选项。SQL 查询在所选方法的命令参数中可用(您应该拦截ReaderExecuted(DbCommand, DbCommandInterceptionContext<DbDataReader>)

OPTION(MAXRECURSION 0)特定于 SQL Server 语法,我认为 EntitySql 永远不会支持这种特定语法。这将使抽象与基础数据存储过于耦合,并且难以支持其他数据库服务器。

如果你达到了一些递归限制,也许审查你的设计是个好主意,因为降低限制应该会使你的问题变得更糟。