CLR表值函数如何“流化”?

| 表值Sql Clr函数上的MSDN文档指出:   Transact-SQL表值函数   实现呼叫的结果   函数插入中间表。   ...相反,CLR表值   函数代表流   替代。没有要求   整个结果集是   在单个表中实现。的   IEnumerable对象返回的   托管函数直接由调用   查询的执行计划   调用表值函数,并且   结果被消耗在   增量方式。 ...这也是   如果您有非常好的选择   返回了大量行,   因为他们不必   在整体内存中实现。 然后我发现\'Fill row \'方法中不允许数据访问。这意味着您仍然必须在init方法中进行所有数据访问,并将其保存在内存中,等待“填充行”被调用。我误会了吗? 如果不将结果强制放入数组或列表中,则会收到错误消息:\'ExecuteReader需要打开且可用的Connection。连接的当前状态已关闭。 代码示例:
[<SqlFunction(DataAccess = DataAccessKind.Read, FillRowMethodName = \"Example8Row\")>]
static member InitExample8() : System.Collections.IEnumerable = 
   let c = cn() // opens a context connection
   // I\'d like to avoid forcing enumeration here:
   let data = getData c |> Array.ofSeq
   data :> System.Collections.IEnumerable

static member Example8Row ((obj : Object),(ssn: SqlChars byref)) = 
   do ssn <- new SqlChars(new SqlString(obj :?> string))
   ()
我在这里处理几百万行。有什么办法可以偷懒地做到这一点吗?     
已邀请:
我假设您使用的是SQL Server2008。正如Microsoft员工在此页上所提到的,2008要求使用DataAccessKind标记方法。读取的频率比2005年要高得多。其中之一是TVF参与其中。交易(当我测试时似乎总是这样)。解决方案是在连接字符串中指定“ 1”,但是不能与“ 2”组合。这意味着您的连接字符串必须采用典型的客户端格式:
Data Source=.;Initial Catalog=MyDb;Integrated Security=sspi;Enlist=false
,并且程序集必须至少以
permission_set=external_access
创建。以下作品:
using System;
using System.Collections;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;

namespace SqlClrTest {
    public static class Test {
        [SqlFunction(
            DataAccess = DataAccessKind.Read,
            SystemDataAccess = SystemDataAccessKind.Read,
            TableDefinition = \"RowNumber int\",
            FillRowMethodName = \"FillRow\"
            )]
        public static IEnumerable MyTest(SqlInt32 databaseID) {
            using (var con = new SqlConnection(\"data source=.;initial catalog=TEST;integrated security=sspi;enlist=false\")) {
                con.Open();
                using (var cmd = new SqlCommand(\"select top (100) RowNumber from SSP1 where DatabaseID = @DatabaseID\", con)) {
                    cmd.Parameters.AddWithValue(\"@DatabaseID\", databaseID.IsNull ? (object)DBNull.Value : databaseID.Value);
                    using (var reader = cmd.ExecuteReader()) {
                        while (reader.Read())
                            yield return reader.GetInt32(0);
                    }
                }
            }
        }
        public static void FillRow(object obj, out SqlInt32 rowNumber) {
            rowNumber = (int)obj;
        }
    }
}
这是F#中的同一件事:
namespace SqlClrTest

module Test =

    open System
    open System.Data
    open System.Data.SqlClient
    open System.Data.SqlTypes
    open Microsoft.SqlServer.Server

    [<SqlFunction(
        DataAccess = DataAccessKind.Read,
        SystemDataAccess = SystemDataAccessKind.Read,
        TableDefinition = \"RowNumber int\",
        FillRowMethodName = \"FillRow\"
        )>]
    let MyTest (databaseID:SqlInt32) =
        seq {
            use con = new SqlConnection(\"data source=.;initial catalog=TEST;integrated security=sspi;enlist=false\")
            con.Open()
            use cmd = new SqlCommand(\"select top (100) RowNumber from SSP1 where DatabaseID = @DatabaseID\", con)
            cmd.Parameters.AddWithValue(\"@DatabaseID\", if databaseID.IsNull then box DBNull.Value else box databaseID.Value) |> ignore
            use reader = cmd.ExecuteReader()
            while reader.Read() do
                yield reader.GetInt32(0)
        } :> System.Collections.IEnumerable

    let FillRow (obj:obj) (rowNumber:SqlInt32 byref) =
        rowNumber <- SqlInt32(unbox obj)
好消息是:Microsoft认为这是一个错误。     
是的,您需要将结果拉入内存,然后从那里返回。尽管这样做的目的是避免您执行此类操作。 您可以在链接到的MSDN文档的各节之一中看到该方法的示例(\“示例:返回SQL查询的结果\”) 尽管实际的电子邮件验证实现将使用标量而不是表函数,但这些示例还是有些虚构的-为每个输入电子邮件值返回布尔值,而不是无效列表的列表。 您能否进一步说明您要达到的目标?构造功能可能有更好的方法。     
您可以做的是用IEnumerable封装SqlDataReader类,该IEnumerable使用一个枚举器,当其\“ Next \”方法被调用时,该枚举器将在SqlDataReader上执行MoveNext并返回SqlDataReader。然后,您的FillRow方法将SqlDataReader期望为一个类。如果您的枚举器在无法再“下一步”时关闭数据库连接和SqlDataReader,那么您已经有效地将输出流式传输到FillRows函数。您也可以使用ContextConnection = true来执行此操作... ...这里的麻烦在于,您必须能够返回实际查询的结果:如果您正在做更复杂的事情来创建结果集,那么您就不走运了。     

要回复问题请先登录注册