无法在Powershell中使用加载的Oracle.ManagedDataAccess程序集

ryoqjall  于 2023-03-29  发布在  Oracle
关注(0)|答案(2)|浏览(177)

我试图使用Powershell和Oracle.ManagedDatabaseAccess.dll连接到现有的Oracle数据库。我使用相同的库在C#中运行代码。程序集已加载,但我无法使用它。
我用的是Win10和Powershell伊势,我也用VS 2017/15.3.2和.Net 4.7.02046。
我尝试使用“Add-Type -AssemblyName”和“Add-Type -Path”,但根本不起作用。两个选项都立即显示错误。
我打电话给

[Reflection.Assembly]::LoadFile("myrootpath\.nuget\packages\oracle.manageddataaccess.core\2.18.5\lib\netstandard2.0\Oracle.ManagedDataAccess.dll")

但我得到了:

GAC    Version        Location 
---    -------        --------                                                                                                                                                                
False   v4.0.30319     C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\Oracle.ManagedDataAccess\v4.0_2.0.18.3__89b483f429c47342\Oracle.ManagedDataAccess.dll

我使用gcautil手动将程序集添加到GAC。

GAC    Version        Location   
---    -------        --------                                                                                                                                                                
True   v4.0.30319     C:\WINDOWS\Microsoft.Net\assembly\GAC_MSIL\Oracle.ManagedDataAccess\v4.0_2.0.18.3__89b483f429c47342\Oracle.ManagedDataAccess.dll

现在当我打电话:

$command = New-Object Oracle.DataAccess.Client.OracleCommand($sql,$conn)

我得到以下错误:

New-Object : The Type [Oracle.ManagedDataAccess.Client.OracleConnection] cannot be found. Make sure that you load the Assembly that contains this Type.
In Line:2 Character:8
+ $conn= New-Object Oracle.ManagedDataAccess.Client.OracleConnection($c ...
+        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidType: (:) [New-Object], PSArgumentException
    + FullyQualifiedErrorId : TypeNotFound,Microsoft.PowerShell.Commands.NewObjectCommand

我读到了编译一个小的C#控制台应用程序的解决方案(因为它可以工作)并从PowerShell调用它。这可能是可行的,但是我真的想了解这里的问题是什么。任何帮助都非常感谢。

更新/编辑:

PS H:\> Add-Type -Path "C:\mypath\Oracle.ManagedDataAccess.dll"
Add-Type : At least one type in the assembly could not be loaded.
    + CategoryInfo          : NotSpecified: (:) [Add-Type], ReflectionTypeLoadException
    + FullyQualifiedErrorId : System.Reflection.ReflectionTypeLoadException,Microsoft.PowerShell.Commands.AddTypeCommand
 
PS H:\> $error[0].Exception.LoaderExceptions[0]
The type "System.IO.Stream" in the assembly "netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51" could not be loaded.

Netstandard2.0.0.0是Oracle.ManagedDataAccess.dll的一个要求,它也必须安装在我的VS项目中。
System.IO.Stream应该可以在PS中使用而无需加载。可能是版本冲突,因为我的主要开发环境是.Net 4.7.02046?

ryhaxcpt

ryhaxcpt1#

首先,您需要确保您使用的NuGet程序集版本与您使用的PowerShell版本兼容。您提到您在PowerShell伊势中编写Windows 10上的代码。由于PowerShell ISE不支持PowerShell Core,并且Windows 10周年纪念版包含5.1 out of the box,因此我假设您正在Windows PowerShell中编写代码,而不是较新的PowerShell Core

这一点很重要,因为在Windows PowerShell 5.1之前,PowerShell是基于.NET Framework的,而在PowerShell Core中,Microsoft切换到了多平台的.NET Core。而且,*Oracle为每个版本发布了不同版本的Oracle数据提供程序 *。
使用.NET Framework(Windows PowerShell 5.1及更低版本)时,请使用Oracle.ManagedDataAccess
使用.NET Core(PowerShell Core 6及更高版本)时,请使用Oracle.ManagedDataAccess.Core

其次,您需要将程序集导入到当前会话中。虽然这听起来很容易,但Oracle有一个绝妙的想法,即对Core和非Core版本(托管和非托管)使用相同的程序集名称,因此您需要使用完整的程序集路径来执行此操作。否则很可能会不可靠地导入不兼容的版本。

幸运的是,您可以将查找程序集和下载程序集(如果缺少)结合起来,仅使用在用户空间中运行的本机PowerShell命令进行快速操作。
1.使用Get-Package检查是否已经安装了ODP.NET并获取其位置。
1.如果返回ObjectNotFound异常,请使用Install-Package从www.example.com下载ODP.NETNuGet.org。
1.如果返回ObjectNotFound异常,请将www.example.com安装NuGet.org为不受信任的PackageProvider。
1.通过Add-Type和程序集路径显式导入新安装的程序集。
然后您就可以在PowerShell中使用ODP.NET了。

示例实现

#Requires -PSEdition Desktop

try { $nugetPkg = (Get-Package Oracle.ManagedDataAccess -ProviderName NuGet -MinimumVersion "19.3.1" -ErrorAction Stop -Debug:$false).Source }
catch [System.Exception] {
    if($_.CategoryInfo.Category -eq "ObjectNotFound") {
        # Register NuGet.org as a package source if it is missing.
        try { Get-PackageSource -Name "nuget.org" -ProviderName NuGet -Debug:$false -ErrorAction Stop }
        catch [System.Exception] {
            if($_.CategoryInfo.Category -eq "ObjectNotFound") {
                Register-PackageSource -Name "nuget.org" -Location "https://www.nuget.org/api/v2/" -ProviderName NuGet -Debug:$false
            }
            else { throw $_ }
        }

        # Install Oracle drivers.
        $pkg = (Install-Package Oracle.ManagedDataAccess -ProviderName NuGet -MinimumVersion "19.3.1" -Verbose -Scope CurrentUser -Force -Debug:$false).Payload.Directories[0]
        $nugetPkg = Join-Path -Path $pkg.Location -ChildPath $pkg.Name
        Remove-Variable pkg
    }
    else { throw $_ }
}
# Add ODP.NET to the assemblies available in-session.  Using the path instead of AssemblyName avoids conflicts with ODP.NET (Core).
# See https://docs.oracle.com/en/database/oracle/oracle-data-access-components/18.3/odpnt/index.html for documentation.
Add-Type -Path (Get-ChildItem (Split-Path ($nugetPkg) -Parent) -Filter "Oracle.ManagedDataAccess.dll" -Recurse -File)[0].FullName

# Begin Query Operations
try {
    # TESTB connection string.  You can replace the Data Source value with a tnsnames alias.
    $con = New-Object Oracle.ManagedDataAccess.Client.OracleConnection(
        "Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=testb)(PORT=1521)) (CONNECT_DATA=(SERVICE_NAME=testb))); User Id=test;Password=user;"
        )
    $con.Open()
    Write-Host ("Connected to database: {0} – running on host: {1} – Servicename: {2} – Serverversion: {3}" -f $con.DatabaseName, $con.HostName, $con.ServiceName, $con.ServerVersion) -ForegroundColor Cyan -BackgroundColor Black

    # Get a single value
    Write-Host "Returning a Scalar Value from Oracle" -ForegroundColor Cyan -BackgroundColor Black
    $cmd = $con.CreateCommand()
    $cmd.CommandText = "SELECT 'Hello World!' FROM DUAL"
    $cmd.ExecuteScalar()

    # Get several defined values
    Write-Host "Retrieving manually typed ordinals from v`$version via OracleDataReader" -ForegroundColor Cyan -BackgroundColor Black
    $cmd.CommandText = 'SELECT BANNER FROM v$version'
    $rdr = $cmd.ExecuteReader()
    while ($rdr.Read()) {
        $rdr.GetString(0)
    }
    $rdr.Dispose()

    # Use a DataAdapter to get defined Data objects.
    Write-Host "Using a DataAdapter to return NLS_SESSION_PARAMETERS from Oracle" -ForegroundColor Cyan -BackgroundColor Black
    $adap = New-Object Oracle.ManagedDataAccess.Client.OracleDataAdapter("SELECT * FROM NLS_SESSION_PARAMETERS",$con)
    # Create the builder for the adapter to automatically generate the Command when needed.
    $oraCmdBldr = New-Object Oracle.ManagedDataAccess.Client.OracleCommandBuilder($adap)
    
    [System.Data.DataSet]$dataset = New-Object System.Data.DataSet
    $adap.Fill($dataset,"NLSSesParams")
    $dataset.Tables["NLSSesParams"]
    Remove-Variable dataset
}
catch {
    Write-Error ("Can't open connection: {0}n{1}" -f $con.ConnectionString, $_.Exception.ToString())
}
finally {
    if ($con.State -eq 'Open') { $con.close() }
    $con.Dispose()
    Write-Host "Disconnected from database" -ForegroundColor Cyan -BackgroundColor Black
}

示例输出

Connected to database: testb – running on host: bat – Servicename: testb – Serverversion: 11.2.0.4.0
Returning a Scalar Value from Oracle
    Hello World!
Retrieving manually typed ordinals from v$version via OracleDataReader
    Oracle Database 11g Release 11.2.0.4.0 - 64bit Production
    PL/SQL Release 11.2.0.4.0 - Production
    CORE    11.2.0.4.0  Production
    TNS for Linux: Version 11.2.0.4.0 - Production
    NLSRTL Version 11.2.0.4.0 - Production
Using a DataAdapter to return NLS_SESSION_PARAMETERS from Oracle
    17

Disconnected from database
    PARAMETER               VALUE                       
    ---------               -----                       
    NLS_LANGUAGE            AMERICAN                    
    NLS_TERRITORY           AMERICA                     
    NLS_CURRENCY            $                           
    NLS_ISO_CURRENCY        AMERICA                     
    NLS_NUMERIC_CHARACTERS  .,                          
    NLS_CALENDAR            GREGORIAN                   
    NLS_DATE_FORMAT         DD-MON-RR                   
    NLS_DATE_LANGUAGE       AMERICAN                    
    NLS_SORT                BINARY                      
    NLS_TIME_FORMAT         HH.MI.SSXFF AM              
    NLS_TIMESTAMP_FORMAT    DD-MON-RR HH.MI.SSXFF AM    
    NLS_TIME_TZ_FORMAT      HH.MI.SSXFF AM TZR          
    NLS_TIMESTAMP_TZ_FORMAT DD-MON-RR HH.MI.SSXFF AM TZR
    NLS_DUAL_CURRENCY       $                           
    NLS_COMP                BINARY                      
    NLS_LENGTH_SEMANTICS    BYTE                        
    NLS_NCHAR_CONV_EXCP     FALSE

可以通过以下方式轻松修改此代码以在PowerShell Core中工作:
1.将#Requires -PSEdition Desktop替换为#Requires -PSEdition Core
1.将安装组件从Oracle.ManagedDataAccess更改为Oracle.ManagedDataAccess.Core
1.将Get-PackageInstall-Package-MinimumVersion参数值从"19.3.1"更改为"2.18.3"

pgpifvop

pgpifvop2#

我将文件'Oracle.ManagedDataAccess.dll'复制到带有ps1脚本(未安装Oracle客户端)的文件夹中,并使用代码:

# powershell script in Windows 10  
using assembly ".\Oracle.ManagedDataAccess.dll"

using namespace Oracle.ManagedDataAccess.Client

$constr = "User Id=user;Password=pass;Data Source=server:1521/sid";
try {
   $con = new-object OracleConnection($constr);
   $con.Open();
} catch {
  write-host "ERROR: $_" -ForegroundColor Red
  exit;
}
$cmdQuery = "SELECT 'Hellow!' FROM dual"
$cmd = new-object OracleCommand($cmdQuery);
$cmd.Connection = $con;
$cmd.CommandType = [System.Data.CommandType]::Text;
try {
    $reader = $cmd.ExecuteReader();
} catch {
     write-host "ERROR: $_" -ForegroundColor Red
     $con.Close();
     $cmd.Dispose();
     $con.Dispose();
     exit;
}

while ($reader.Read()) {
        write-host $reader.GetString(0)
    } ;
$con.Close();
$cmd.Dispose();
$con.Dispose();

相关问题