Использование Entity Framework 6 / EF Core внутри SQL CLR - PullRequest
2 голосов
/ 30 июня 2019

Техническая поддержка Microsoft Azure подтвердила , что все версии .Net 4.XX, включая 4.7.2, поддерживаются в управляемом экземпляре SQL Server.

Мы преобразовываем некоторую частьБизнес-уровень с 4.7.2 и более поздними версиями EF 6.2

Использование Entity Framework в CLR Хранимая процедура

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

Следовательно, чтобы использовать существующиеинвестируя в хорошо протестированный код, мы хотим переместить определенный бизнес-уровень в БД.

Однако при публикации мы столкнулись с проблемами.

Создание [System.Dynamic] ...

Предупреждение. Сборка Microsoft .NET Framework 'system.dynamic, версия = 4.0.0.0, культура = нейтральная, publickeytoken = b03f5f7f11d50a3a.'

Вы регистрируетесь не полностьюпротестировано в среде размещения SQL Server и не поддерживается.В будущем, если вы обновите или обслужите эту сборку или .NET Framework, ваша процедура интеграции CLR может перестать работать.Дополнительные сведения см. В электронной документации по SQL Server.

(47,1): SQL72014: поставщик данных .Net SqlClient:

Msg 6218, уровень 16, состояние 2, строка 1
CREATE ASSEMBLY для сборки «System.Dynamic» не выполнен, поскольку сборка «System.Dynamic» не прошла проверку. Проверьте, являются ли указанные сборки актуальными и надежными (для external_access или unsafe) для выполнения в базе данных.
Сообщения об ошибках CLR Verifier, если таковые будут следовать за этим сообщением [:
System.Dynamic.ArgBuilder :: MarshalToRef] [mdToken = 0x6000002] [offset 0x00000000] Размер кода равен нулю.[: System.Dynamic.ArgBuilder :: UnmarshalFromRef] [mdToken = 0x6000003] [offset

PS (ИМХО, неважно, если ядро ​​EF также, тем не менее мы пробуем это с EF6.2)

РЕДАКТИРОВАТЬ: дали разрешение UNSAFE на все сборки, на которые я ссылаюсь: Вот все зависимости:

enter image description here

<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 enter image description here

РЕДАКТИРОВАТЬ 4:

  • Стоп-шоу: System.RunTime.Serialization,
CREATE ASSEMBLY [System.Runtime.Serialization]
    AUTHORIZATION [dbo]
    FROM 0x4D5...
    WITH PERMISSION_SET = UNSAFE;

, что мешает мне создавать UNSAFE-сборки Entity Framework в БД.Можем ли мы пройти через 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, версия = 4.0.0.0, культура = нейтральная, publickeytoken = b77a5c561934e089«.Ваша регистрация не полностью протестирована в среде, размещенной на SQL Server, и не поддерживается.В будущем, если вы обновите или обслужите эту сборку или .NET Framework, ваша процедура интеграции CLR может перестать работать.Пожалуйста, обратитесь к электронной документации по SQL Server для более подробной информации.Сообщение 6218, уровень 16, состояние 2, строка 11 СОЗДАТЬ СБОРКУ для сборки «System.Runtime.Serialization» не удалось, поскольку сборка «System.Runtime.Serialization» не прошла проверку .Проверьте, являются ли указанные сборки современными и надежными (для external_access или unsafe) для выполнения в базе данных.Сообщения об ошибках CLR Verifier, если таковые будут следовать за этим сообщением [: System.AppContextDefaultValues ​​:: PopulateDefaultValues] [mdToken = 0x6000001] [offset 0x00000000] Размер кода равен нулю.

Ответы [ 2 ]

1 голос
/ 30 июня 2019

Техническая поддержка Microsoft Azure подтвердила, что все версии .Net 4.XX, включая 4.7.2, поддерживаются в CLR управляемого сервера SQL Server

Управляемый экземпляр использует последнюю версию.NET Framework для размещения сборок SQL CLR.Это не означает, что он поддерживает загрузку непроверенных сборок .NET Framework.См. Заявление в службу поддержки здесь .

Кроме того, управляемый экземпляр не разрешает сборки UNSAFE CLR, поскольку они позволяют запускать произвольный код и получать прямой доступ к ресурсам сервера.

Даже если вы сможете загрузить все эти сборки .NET Framework в свою базу данных, это не будет поддерживаемым решением в управляемом экземпляре.Как ясно из приведенного выше заявления о поддержке, вы должны сохранять копии сборок .NET Framework, загруженных в вашу базу данных, синхронно с версией .NET Framework на сервере..NET Framework на сервере обновляется в обновлениях Windows.Когда вы управляете сервером, поддерживать ваши сборки в синхронизации с версией в Windows достаточно сложно.Но когда Microsoft исправляет сервер, у вас нет возможности узнать, что вам нужно обновить ваши сборки.

При работе на виртуальной машине Azure вы сможете установить все сборки, которые требуются EF.Единственное ограничение в ВМ заключается в том, что вы не можете загружать сборки в смешанном режиме, но я не думаю, что EF (в настоящее время) полагается на какую-либо из них.Если вы приступите к работе с решением, включающим сборки .NET Framework, загруженные в вашу базу данных, вам, вероятно, следует реализовать запускающую хранимую процедуру или запланированную задачу, которая обновляет сборки вашей базы данных из папки Windows .NET Framework каждый раз, когда SQLСервер запускается.

В любом случае, вот сценарий powershell. Мне удалось загрузить EF6 и его зависимости в базу данных SQL Server.Но помните, то, что вы можете загрузить сборку, не означает, что она будет работать правильно.Вам нужно будет тщательно протестировать, чтобы определить, будет ли ваш EF-код действительно работать.

Но запуск вашего .NET-кода на вашем SQL Server необычен и обычно является плохой идеей.Это очень близко к вашим данным, но это отдельная виртуальная машина в той же виртуальной сети.Это усложняет управление вашим 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()
1 голос
/ 30 июня 2019

Хост CLR SQL Server будет использовать самую высокую версию .NET Framework, установленную в системе, для той версии CLR, с которой он связан.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.

При этом некоторые библиотеки Framework являются встроенными и не требуют добавления вручную.,Они перечислены здесь:

Поддерживаемые библиотеки .NET Framework

Если вам нужна библиотека, которой нет в этом списке, вы можете добавить ее самостоятельно, , но это не значит, что вы можете добавить просто любую библиотеку.SQL Server допускает только чистые библиотеки MSIL, а не смешанный режим (mixed = содержит как управляемый, так и неуправляемый код).Если вам требуется библиотека в смешанном режиме, то вы ничего не сможете сделать, чтобы загрузить ее в SQL Server.ТАКЖЕ, имейте в виду, что даже если сегодня библиотека является чистым MSIL, это не означает, что она не может быть преобразована в смешанный режим в будущем обновлении Framework (и да, это произошло).

Учитывая все это, следующий элемент в сообщении об ошибке:

Размер кода равен нулю.

, вероятно, указывает на то, что вы пытаетесь загрузить справочную библиотеку,Вам нужно загрузить фактическую библиотеку, а не ее эталонную версию.

Я попробовал следующее на 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 будет достаточно.

Iне было библиотек EntityFramework для загрузки, но ошибка, которую вы получаете, находится на первой, а операторы, которые я разместил выше, не получают эту ошибку.Если вы можете выполнить эти 2 оператора, чтобы загрузить все 5 библиотек, а затем получить ошибку на EntityFramework, мы рассмотрим конкретное сообщение об ошибке.

HOWEVER, , даже если вы можете загрузить все эти библиотеки DLL, включая две для EntityFramework, это не является гарантией того, что вы действительно сможете использовать EF.Возможно, что EF не может работать в SQLCLR.Я не могу вспомнить об EF конкретно, но я знаю, что SMO, например, включает в себя код, чтобы определить, работает ли он в SQL Server, и если это так, то возникнет исключение, указывающее, что он не разрешен для запускав SQL Server.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...