回答

收藏

SQL CLR:流式处理表值函数结果

技术问答 技术问答 237 人阅读 | 0 人回复 | 2023-09-14

我使用的是SQL Server 2005 Service Pack2(SP2)(v9.0.3042)那里发布的解决方案对我没有影响。我试着用两个连接字符串。我的一个代码被注释了。
/ }2 R2 c. g. I. G我意识到我可以将所有结果存储在内存中List或ArrayList中间,然后返回。我已经成功地做到了,但这不是这里的目标。目标是在结果可用的时流传输。
; p7 b  D$ i8 F: W  ~* Y! B使用我的SQL Server版本可以吗?
2 R6 K/ ^) ^) n/ ^这是我的代码:(请注意,当前实际上并没有使用这些参数。我这样做是为了进行调试)+ ?6 T6 j& e0 `- N
public static class StoredProcs{    [SqlFunction(         DataAccess = DataAccessKind.Read,       SystemDataAccess=SystemDataAccessKind.Read,       FillRowMethodName="FillBaseline",       TableDefinition = "[baseline_id] [int],[baseline_name] [nvarchar](256),[description] [nvarchar](max),[locked] [bit]"        )public static IEnumerable fnGetBaselineByID(SqlString projectName,SqlInt32 baselineID)                                                                                                                                                                                                                 string connStr = "context connection=true";      string connStr = "data source=.;initial catalog=DBName;integrated security=SSPI;enlist=false";        using (SqlConnection conn = new SqlConnection(connStr))                                                                                                                                                                                                                         conn.Open();            using (SqlCommand cmd = new SqlCommand(String.Format(@"                SELECT *                FROM [DBName].[dbo].[Baseline] WITH (NOLOCK)            "),conn))                                                   using (SqlDataReader reader = cmd.ExecuteReader())                                                           while (reader.Read())                                                                   yield return new Baseline(reader);                                              ;       ;public static void FillBaseline(Object obj,out SqlInt32 id,out SqlString name,out SqlString description,out bool locked)                                                                                                                                                                                                                 Baseline baseline = (Baseline)obj;        id = baseline.mID;        name = baseline.nName;        description = baseline.mDescription;        locked = baseline.mLocked;   这是我的SQL部署脚本的一部分:1 z, Z* t: W& e7 N, {! C
CREATE ASSEMBLY [MyService_Stored_Procs]FROM 'C:\temp\assemblyName.dll'WITH PERMISSION_SET = SAFE当我使用连接字符串时, context connection = true这个错误发生在时:1 |  ?- L  U+ q4 f5 d' [' z9 F  ~
从用户定义的表值函数中获取新行时出现错误:System.InvalidOperationException:数据访问不在上下文中访问。上下文是无用的DataAccessKind.Read或SystemDataAccessKind.Read标记的函数或方法来自表值函数FillRow获取数据回调的方法,还是UDT验证方法。% Y7 D+ _: O; n5 S9 D1 \0 l. ~
当我使用其他连接字符串时,出现了这个错误:
9 D+ t* |$ o, \* b6 i从用户定义的表值函数中获取新行时出现错误:System.Security.SecurityException:请求类型为’System.Data.SqlClient.SqlClientPermission,System.Data,Version/ |6 U8 ^/ U- |( {" E
= 2.0.0.0,Culture = neutral,PublicKeyToken的权限= b77a5c561934e089’失败。6 z) H8 _7 Z4 @# h' {6 n9 k  X3 b
                                                                ( j, o) M) T5 S  Z, ]# \) R
    解决方案:                                                               
& G! S8 O) y$ }' t" ]! X3 X+ y                                                                经过进一步的研究和反复的实验,我找到了解决方案。我在这里提到的文章$ A+ t9 g$ X4 a5 |
您的程序集必须使用Permission_set = external_access创建% Q& y1 }- l0 N& I. R7 B
说起来容易做起来难,但这是一个很好的起点。只需用银行代替它。permission_set = safe会出错:5 o5 ]  h0 g: V( d* l& J
assemblyName”创建组件失败,因 assemblyName”未获得PERMISSION_SET =+ {+ [+ g% f) U1 G# U5 L
EXTERNAL_ACCESS授权。如果满足以下任何条件,则授权程序集:数据库所有者(DBO)具有EXTERNAL ACCESS  \/ L, L, I# Z; J
ASSEMBLY数据库有权限TRUSTWORTHY数据库属性。或者使用相应的登录名称EXTERNAL ACCESS* [/ p6 U0 h7 v+ [& p6 F: t
ASSEMBLY相应的权限证书或非对称密钥签署程序集。
* ~& C0 f! ~6 h( p1 k因此,我要做的第一件事是对我的dll签署文件。为此,请在这里Visual Studio# G' O! G8 F0 ~6 F/ b# G  R$ r
2010年将签名选项卡转入项目属性,然后选择签名程序集并命名。对于这个例子,名字是MyDllKey。我选择不使用密码来保护它。当然,我会dll复制文件sql0 h, v( R+ E3 `2 a5 d! J% F' v
server:C:\ Temp
/ `0 G. M5 N, O- l; X, l以此页面为参考,基于上述键创建了以下三个命令SQL登录名:
$ y2 ^3 o- c$ ?6 u; fCREATE ASYMMETRIC KEY MyDllKey FROM EXECUTABLE FILE = 'C:\Temp\MyDll.dll'CREATE LOGIN MyDllLogin FROM ASYMMETRIC KEY MyDllKeyGRANT EXTERNAL ACCESS ASSEMBLY TO MyDllLogin创建登录名后,我现在可以使用以下命令来创建程序集:0 C5 q3 s$ M) B7 |8 d% _/ k* X# ~7 J
CREATE ASSEMBLY [MyDll]FROM 'C:\Temp\MyDll.dll'WITH PERMISSION_SET = EXTERNAL_ACCESS剩下的就是使用正确的连接字符串。显然不是enlist=false与结合使用connection=true。这是我使用的连接字符串的例子。
- L- K$ B6 X- L4 g5 I8 gstring connStr = @"data source=serverName\instanceName;initial catalog=DBName;integrated security=SSPI;enlist=false";而且有效!
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则