2

我正在尝试使用 Powershell 和 Oracle.ManagedDatabaseAccess.dll 连接到现有的 oracle 数据库。我使用相同的库在 C# 中运行代码。程序集已加载,但我无法使用它。

我正在使用 Win10 和 Powershell ISE。我还使用 VS2017/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?

4

1 回答 1

3

首先,您需要确保您使用的 NuGet 程序集版本与您使用的 PowerShell 版本兼容。您提到您在 PowerShell ISE 中的 Windows 10 上编写代码。由于 PowerShell ISE 不支持 PowerShell Core 并且 Windows 10 Anniversary 包括开箱即用的5.1 ,我将假设您在 Windows PowerShell 中编写代码,而不是较新的PowerShell Core

这很重要,因为直到 Windows PowerShell 5.1,PowerShell 都基于 .NET Framework,而使用 PowerShell Core,Microsoft 切换到多平台 .NET Core。碰巧的是,Oracle 为每个.

使用 .NET Framework(Windows PowerShell 5.1 及更低版本)时,使用Oracle.ManagedDataAccess
使用 .NET Core(PowerShell Core 6 及更高版本)时,使用Oracle.ManagedDataAccess.Core

其次,您需要将程序集导入当前会话。虽然这听起来很容易,但 Oracle 有一个绝妙的主意,即为核心和非核心版本、托管和非托管使用相同的程序集名称,因此您将希望使用完整的程序集路径来做到这一点。否则,您可能会不可靠地导入不兼容的版本。

幸运的是,您可以仅使用在用户空间中运行的本机 PowerShell 命令将查找程序集和下载程序集(如果丢失)结合起来进行快速操作。

  1. 用于Get-Package检查是否已安装 ODP.NET 并获取其位置。
  2. 如果ObjectNotFound返回异常,请使用Install-Package.
  3. 如果ObjectNotFound返回异常,请将 NuGet.org 安装为不受信任的 PackageProvider。
  4. 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
  2. 将安装程序集从更改Oracle.ManagedDataAccessOracle.ManagedDataAccess.Core
  3. 将和的-MinimumVersion参数值从更改为。Get-PackageInstall-Package"19.3.1""2.18.3"
于 2019-08-02T19:28:36.103 回答