簡體   English   中英

在 SQL CLR 中使用 Entity Framework 6 / EF Core

[英]Using Entity Framework 6 / EF Core inside SQL CLR

Microsoft Azure 技術支持已確認 SQL Server 托管實例 CLR支持所有版本的 .Net 4.XX,包括 4.7.2

我們正在使用 4.7.2 和最新的 EF 6.2 轉換業務層的某些部分

在 CLR 存儲過程中使用實體框架

https://patrickdesjardins.com/blog/how-to-use-third-party-dll-reference-in-a-sql-clr-function

因此,為了利用對經過良好測試的代碼的現有投資,我們希望將某些業務層移動到 DB 中。

然而,我們在發布時遇到了問題。

正在創建 [System.Dynamic]...

警告:Microsoft .NET Framework 程序集“system.dynamic,version=4.0.0.0,culture=neutral,publickeytoken=b03f5f7f11d50a3a”。

您正在注冊的 SQL Server 托管環境未經過全面測試,不受支持。 將來,如果您升級或維護此程序集或 .NET Framework,您的 CLR 集成例程可能會停止工作。 有關詳細信息,請參閱 SQL Server 聯機叢書。

(47,1):SQL72014:.Net SqlClient 數據提供程序:

消息 6218,級別 16,狀態 2,第 1 行
為程序集“System.Dynamic”創建程序集失敗,因為程序集“System.Dynamic”驗證失敗。 檢查引用的程序集是否是最新的並且受信任(對於 external_access 或不安全)以在數據庫中執行。
CLR 驗證器錯誤消息(如果有)將跟隨此消息 [:
System.Dynamic.ArgBuilder::MarshalToRef][mdToken=0x6000002][offset 0x00000000] 代碼大小為零。 [ : System.Dynamic.ArgBuilder::UnmarshalFromRef][mdToken=0x6000003][偏移量

PS(恕我直言,EF核心也沒關系,盡管如此,我們正在使用EF6.2嘗試此操作)

編輯:已向我所指的所有程序集授予 UNSAFE 權限:以下是所有依賴項:

在此處輸入圖片說明

<ItemGroup>
    <Reference Include="Microsoft.CSharp">
      <HintPath>..\packages2019\dotnet 4.7.2\Microsoft.CSharp.dll</HintPath>
                <SqlPermissionSet>UNSAFE</SqlPermissionSet>
      <GenerateSqlClrDdl>True</GenerateSqlClrDdl>
      <IsModelAware>True</IsModelAware>
      <SpecificVersion>True</SpecificVersion>
    </Reference>
    <Reference Include="System.Dynamic">
      <HintPath>..\packages2019\dotnet 4.7.2\System.Dynamic.dll</HintPath>
                <SqlPermissionSet>UNSAFE</SqlPermissionSet>
      <GenerateSqlClrDdl>True</GenerateSqlClrDdl>
      <IsModelAware>True</IsModelAware>
      <SpecificVersion>True</SpecificVersion>
    </Reference>
    <Reference Include="System.Runtime.Serialization">
      <HintPath>..\packages2019\dotnet 4.7.2\System.Runtime.Serialization.dll</HintPath>
                <SqlPermissionSet>UNSAFE</SqlPermissionSet>
      <GenerateSqlClrDdl>True</GenerateSqlClrDdl>
      <IsModelAware>True</IsModelAware>
      <SpecificVersion>True</SpecificVersion>
    </Reference>
    <Reference Include="SMDiagnostics">
      <HintPath>..\packages2019\v4.0.30319\SMDiagnostics.dll</HintPath>
                <SqlPermissionSet>UNSAFE</SqlPermissionSet>
      <GenerateSqlClrDdl>True</GenerateSqlClrDdl>
      <IsModelAware>True</IsModelAware>
      <SpecificVersion>True</SpecificVersion>
    </Reference>
    <Reference Include="System.ServiceModel.Internals">
      <HintPath>..\packages2019\v4.0.30319\System.ServiceModel.Internals.dll</HintPath>
                <SqlPermissionSet>UNSAFE</SqlPermissionSet>
      <GenerateSqlClrDdl>True</GenerateSqlClrDdl>
      <IsModelAware>True</IsModelAware>
      <SpecificVersion>True</SpecificVersion>
    </Reference>
      <Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
      <HintPath>..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.dll</HintPath>
            <SqlPermissionSet>UNSAFE</SqlPermissionSet>
      <SpecificVersion>True</SpecificVersion>
      <IsModelAware>True</IsModelAware>
      <GenerateSqlClrDdl>True</GenerateSqlClrDdl>
    </Reference>
    <Reference Include="EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
      <HintPath>..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.SqlServer.dll</HintPath>
            <SqlPermissionSet>UNSAFE</SqlPermissionSet>
      <SpecificVersion>True</SpecificVersion>
      <IsModelAware>True</IsModelAware>
      <GenerateSqlClrDdl>True</GenerateSqlClrDdl>
    </Reference>

編輯 3:Azure SQL Server MI 中的不安全代碼在此處輸入圖片說明

編輯 4:

  • 顯示停止器是: System.RunTime.Serialization
 CREATE ASSEMBLY [System.Runtime.Serialization] AUTHORIZATION [dbo] FROM 0x4D5... WITH PERMISSION_SET = UNSAFE;

這阻止我將實體框架 UNSAFE 程序集創建到數據庫中。 我們可以通過 system.Runtime.Serialization 嗎?

GO
CREATE ASSEMBLY [EntityFramework]
    AUTHORIZATION [dbo]
    FROM 0x4D5A90...
    WITH PERMISSION_SET = UNSAFE;


GO
PRINT N'Creating [EntityFramework.SqlServer]...';


GO
CREATE ASSEMBLY [EntityFramework.SqlServer]
    AUTHORIZATION [dbo]
    FROM 0x4...
    WITH PERMISSION_SET = UNSAFE;

警告:Microsoft .NET Framework 程序集“system.runtime.serialization,version=4.0.0.0,culture=neutral,publickeytoken=b77a5c561934e089”。 您正在注冊的未在 SQL Server 托管環境中進行全面測試,因此不受支持。 將來,如果您升級或維護此程序集或 .NET Framework,您的 CLR 集成例程可能會停止工作。 有關詳細信息,請參閱 SQL Server 聯機叢書。 消息 6218,級別 16,狀態 2,第 11 行為程序集“System.Runtime.Serialization”創建程序集失敗,因為程序集“System.Runtime.Serialization”驗證失敗 檢查引用的程序集是否是最新的並且受信任(對於 external_access 或不安全)以在數據庫中執行。 CLR 驗證器錯誤消息(如果有)將跟隨此消息 [ : System.AppContextDefaultValues::PopulateDefaultValues][mdToken=0x6000001] [offset 0x00000000] 代碼大小為零。

對於鏈接到的 CLR 版本,SQL Server 的 CLR 主機將使用系統上安裝的最高版本的 .NET Framework。 SQL Server 2005 - 2008 R2 鏈接到 CLR 2.0 版,因此它們將使用 .NET Framework 2.0、3.0 和 3.5 版。 SQL Server 2012 和更新版本都鏈接到 CLR 4.0 版,因此將使用 .NET Framework 4.x 版。

話雖如此,一些框架庫是內置的,不需要手動添加。 這些在此處列出:

支持的 .NET Framework 庫

如果您需要一個不在該列表中的庫,您可以自己添加它,但這並不意味着您可以添加任何庫。 SQL Server 只允許純 MSIL 庫,而不是混合模式(混合 = 包含托管和非托管代碼)。 如果您需要一個混合模式的庫,那么您無法將其加載到 SQL Server 中。 另外,請記住,即使庫今天是純 MSIL,這並不意味着它不能在未來的框架更新中轉換為混合模式(是的,這已經發生了)。

考慮到所有這些,錯誤消息中的以下項目:

代碼大小為零。

可能表示您正在嘗試加載參考庫。 您需要加載實際的庫,而不是它的參考版本。

我在 SQL Server 2017 上嘗試了以下操作,並且能夠將它們全部加載,盡管並非所有都需要顯式加載。 有些會自動加載其他的,因為它們在同一個文件夾中:

CREATE ASSEMBLY [Microsoft.CSharp]
FROM 'C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.CSharp.dll'
WITH PERMISSION_SET = UNSAFE;
-- includes System.Dynamic


CREATE ASSEMBLY [System.Runtime.Serialization]
FROM 'C:\Windows\Microsoft.NET\Framework64\v4.0.30319\System.Runtime.Serialization.dll'
WITH PERMISSION_SET = UNSAFE;
-- includes SMDiagnostics, System.ServiceModel.Internals

然后檢查:

SELECT * FROM sys.assemblies;
/*
Microsoft.CSharp
System.Dynamic
System.Runtime.Serialization
System.ServiceModel.Internals
SMDiagnostics
*/

請注意,目前,我將數據庫設置為TRUSTWORTHY ON 這不是我通常推薦的,也可能不是必需的,但在我完成我的帖子處理如何正確和輕松地處理這個問題之前, TRUSTWORTHY就足夠了。

我沒有要加載的 EntityFramework 庫,但是您遇到的錯誤是第一個,而我上面發布的語句沒有出現該錯誤。 如果您能夠執行這 2 條語句以加載所有 5 個庫,然后在 EntityFramework 上出現錯誤,那么我們將查看具體的錯誤消息。

但是,即使您能夠加載所有這些 DLL,包括 EntityFramework 的兩個 DLL,也不能保證您實際上能夠使用 EF。 EF 可能無法在 SQLCLR 中運行。 我不記得具體的 EF,但我確實知道,例如,SMO 包含用於檢測它是否在 SQL Server 中運行的代碼,如果是,則它會引發異常,指出它不允許運行在 SQL Server 中。

Microsoft Azure 技術支持已確認 SQL Server 托管實例 CLR 支持所有版本的 .Net 4.XX,包括 4.7.2

托管實例使用最新版本的 .NET Framework 來承載 SQL CLR 程序集。 這並不意味着它支持加載未經測試的 .NET Framework 程序集。 請參閱此處的支持聲明。

此外,托管實例不允許使用 UNSAFE CLR 程序集,因為它們將使您能夠運行任意代碼並直接訪問服務器資源。

即使您可以將所有這些 .NET Framework 程序集加載到您的數據庫中,它也不是托管實例中可支持的解決方案。 正如上面的支持聲明所表明的那樣,您必須使加載到數據庫中的 .NET 框架程序集副本與服務器上的 .NET 框架版本保持同步。 服務器上的 .NET Framework 在 Windows 更新中更新。 當您管理服務器時,使程序集與 Windows 中的版本保持同步已經夠難了。 但是當微軟正在修補服務器時,您無法知道您需要更新您的程序集。

在 Azure VM 上運行時,您將能夠安裝 EF 所需的所有程序集。 VM 中的唯一限制是您不能加載混合模式程序集,但我認為 EF(當前)不依賴於其中任何一個。 如果您使用涉及加載到數據庫中的 .NET Framework 程序集的解決方案進入生產,您可能應該實施啟動存儲過程或計划任務,以便在每次 SQL Server 啟動時從 Windows .NET Framework 文件夾刷新您的數據庫程序集。

無論如何,這里有一個 powershell 腳本,我能夠將 EF6 及其依賴項加載到 SQL Server 數據庫中。 但請記住,僅僅因為您可以加載程序集,並不意味着它會正常工作。 您必須進行廣泛的測試,以確定您的 EF 代碼是否真的可以工作。

但是在 SQL Server 上運行 .NET 代碼並不常見,而且通常是個壞主意。 它與您的數據非常接近,但同一 VNet 上的單獨 VM 也是如此。 它使您的 SQL Server 更難管理,並且通常有更簡單的方法可以通過在 SQL Server 上運行代碼來完成您希望獲得的任何內容,

而且,如果您在 SQL Server 上本地運行代碼,那么它可能沒有充分的理由必須是 SQL CLR。 您可以在控制台應用程序中運行您的代碼並使用xp_cmdshell或 SQL 代理作業觸發它。

無論如何,這是用於注冊程序集的powershell:

$constr = "server=localhost;database=clrtest;integrated security=true"
$folder = "C:\Users\dbrowne\Source\Repos\SqlClrTest\ClassLibrary1\bin\Debug"
$netfx = "C:\Windows\Microsoft.NET\Framework64\v4.0.30319"

$dlls = @(
    "system.dynamic",
    "microsoft.csharp",
    "system.componentmodel.dataannotations",
    "smdiagnostics",
    "system.servicemodel.internals",
    "system.runtime.serialization", 
    "entityframework",
    "entityframework.sqlserver",
    "YourClassLibrary",
    "YourSqlClrProject"
    )


[System.Data.SqlClient.SqlConnection]$con = New-Object System.Data.SqlClient.SqlConnection $constr
$con.Open()

[System.Data.SqlClient.SqlCommand] $cmd = $con.CreateCommand()
$cmd.CommandText = @"

    if cast(serverproperty('ProductMajorVersion') as int) >= 14
    begin


        DECLARE @hash varbinary(64);

        SELECT @hash = HASHBYTES('SHA2_512', @assemblyFile);

        declare @description nvarchar(4000) = @name

        if not exists (select * from sys.trusted_assemblies where hash = @hash)
        begin
          EXEC sys.sp_add_trusted_assembly @hash = @hash,
                                           @description = @description;
          print 'trusted assembly added'
        end

    end

   declare @sql nvarchar(max) 

   if exists (select * from sys.assemblies where name = @name)
   begin

        set @sql =  concat('
        alter assembly ',quotename(@name),'
        FROM @assemblyFile
        WITH PERMISSION_SET = UNSAFE;  
        ')
       EXECUTE sp_executesql @sql, N'@assemblyFile varbinary(max)', @assemblyFile = @assemblyFile;
       print 'updated assembly ' + @name
   end
   else
   begin

        set @sql =  concat('
        create assembly ',quotename(@name),'
        AUTHORIZATION [dbo]
        FROM @assemblyFile
        WITH PERMISSION_SET = UNSAFE;  
        ')

       EXECUTE sp_executesql @sql, N'@assemblyFile varbinary(max)', @assemblyFile = @assemblyFile;
       print 'added assembly ' + @name

   end


"@

$pName = $cmd.Parameters.Add("@name", [System.Data.SqlDbType]::NVarChar, 1000)
$pAssemblyFile = $cmd.Parameters.Add("@assemblyFile", [System.Data.SqlDbType]::VarBinary, -1)



foreach ($targetDll in $dlls)
{
    try
    {
       $pName.Value = $targetDll
       if ([System.IO.File]::Exists("$folder\$targetDll.dll"))
       {
          $pAssemblyFile.Value = [System.IO.File]::ReadAllBytes("$folder\$targetDll.dll")
       }
       else
       {
          $pAssemblyFile.Value = [System.IO.File]::ReadAllBytes("$netfx\$targetDll.dll")

       }

       $result = $cmd.ExecuteNonQuery()

    }
    catch [System.Data.SqlClient.SqlException]
    {
       [System.Data.SqlClient.SqlException] $ex = $_.Exception

       write-host "$($ex.Class) $($ex.Number) $($ex.Message) "

       write-host ""

       continue;
    }
}
$con.Close()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM