2011-08-01 47 views
3

我的問題是非常相似的this問題。SQL CLR:流表值函數的結果

不過,我使用SQL Server 2005的Service Pack 2(SP2)(v9.0.3042)和解決方案張貼有沒有爲我工作。我試着使用兩個連接字符串。其中一個在我的代碼中被註釋掉了。

我知道我可以存儲在內存中的列表或ArrayList中所有的結果並返回。我已經成功完成了這一目標,但這不是目標。我們的目標是能夠在可用時傳輸結果。

這可能使用我的版本的SQL Server?

這裏是我的代碼: (注意參數實際上並沒有被目前使用的我這樣做了調試。)

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部署腳本的一部分:

CREATE ASSEMBLY [MyService_Stored_Procs] 
FROM 'C:\temp\assemblyName.dll' 
WITH PERMISSION_SET = SAFE 

當我使用連接字符串「context connection = true」時,出現此錯誤:

An error occurred while getting new row from user defined Table Valued Function : System.InvalidOperationException: Data access is not allowed in this context. Either the context is a function or method not marked with DataAccessKind.Read or SystemDataAccessKind.Read, is a callback to obtain data from FillRow method of a Table Valued Function, or is a UDT validation method.

當我使用其他連接字符串我得到這個錯誤:

An error occurred while getting new row from user defined Table Valued Function : System.Security.SecurityException: Request for the permission of type 'System.Data.SqlClient.SqlClientPermission, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed.

回答

5

在進一步的研究和反覆試驗,我發現我的解決方案。該article that I mentioned here

your assembly must be created with permission_set=external_access

這比做更容易說,但他是一個很好的起點。只需用該行的地方PERMISSION_SET的=安全提供了錯誤:

CREATE ASSEMBLY for assembly 'assemblyName' failed because assembly 'assemblyName' is not authorized for PERMISSION_SET = EXTERNAL_ACCESS. The assembly is authorized when either of the following is true: the database owner (DBO) has EXTERNAL ACCESS ASSEMBLY permission and the database has the TRUSTWORTHY database property on; or the assembly is signed with a certificate or an asymmetric key that has a corresponding login with EXTERNAL ACCESS ASSEMBLY permission.

所以我必須做的第一件事就是登錄我的dll文件。要在Visual Studio 2010中執行此操作,請轉到項目屬性簽名選項卡,然後選中「簽署程序集」併爲其命名。對於這個例子,名字是MyDllKey。我選擇不使用密碼來保護它。然後,當然,我複製的DLL文件到SQL Server:C:\溫度

使用this page作爲參考,我創建使用這些3個命令基於上述密鑰SQL登錄:

CREATE ASYMMETRIC KEY MyDllKey FROM EXECUTABLE FILE = 'C:\Temp\MyDll.dll' 
CREATE LOGIN MyDllLogin FROM ASYMMETRIC KEY MyDllKey 
GRANT EXTERNAL ACCESS ASSEMBLY TO MyDllLogin 

一旦登錄被創建爲上面,我現在可以創建一個使用這個組件:

CREATE ASSEMBLY [MyDll] 
FROM 'C:\Temp\MyDll.dll' 
WITH PERMISSION_SET = EXTERNAL_ACCESS 

現在唯一剩下要做的就是使用正確的連接字符串。顯然使用enlist=falseconnection=true組合是不可能的。這是我使用的連接字符串的一個例子。

string connStr = @"data source=serverName\instanceName;initial catalog=DBName;integrated security=SSPI;enlist=false"; 

它的工作原理!

2

原來的問題是由於你的函數中使用yield關鍵字,因爲在這一問題解釋說:SqlFunction fails to open context connection despite DataAccessKind.Read present

如果避免使用yield(將結果存儲在中間數組中,最後返回整個批次),問題就會消失。

或者您可以按照您的描述進行操作,並避免使用上下文連接,但是如果您這樣做,必須按照您的描述將外部訪問標記爲程序集。我認爲這是最好的解決方法,而不是一個解決方案,因爲你輸了some of the benefits available from a context connection,因爲你必須跳過所有額外的籃球。

在許多情況下,能夠使用流式傳輸行爲(yield)的好處確實勝過了這種痛苦,但它仍然值得考慮這兩種選擇。

這裏有連接錯誤:谷歌搜索這http://connect.microsoft.com/SQLServer/feedback/details/442200/sql-server-2008-clr-tvf-data-access-limitations-break-existing-code

+0

廢話,我在浪費了半天的時間才發現這個問題,問題一直是「收益」。 – Patrick

0

Data access is not allowed in this context. Either the context is a function or method not marked with DataAccessKind.Read or SystemDataAccessKind.Read, is a callback to obtain data from FillRow method of a Table Valued Function, or is a UDT validation method.

使我這個網頁,但沒有答案,我需要的。
我終於弄清楚它是什麼。
在我的CLR函數中,我調用了另一個Method並傳入了Function所接收的值。

聲音無傷大雅,但我所做的是對我添加的方法的輸入參數使用了相同的數據類型(SqlChars,SqlBoolean,SqlInt32)。

private static ArrayList FlatFile(SqlChars Delimeter, SqlChars TextQualifier) 

顯然使用這些數據類型超過一個CLR SqlFunction任何其他或SqlProcedure有時可以給你這種神祕的錯誤的。

一旦我在我的新方法中刪除了這些數據類型並使用了C#方法(string,bool,int),錯誤終於消失了。

private static ArrayList FlatFile(string Delimeter, string TextQualifier) 

注:此出錯時,我用模擬搶從另一個域中的文件。
當我通過本地域流式傳輸文件時,我沒有收到這個錯誤,這是什麼讓我失望。

我希望這可以幫助你在你需要的時間。解決這個問題我花了太多時間。