ID do artigo: 910696 - Última revisão: quarta-feira, 28 de novembro de 2007 - Revisão: 2.1

Problemas conhecidos para o ADODB Primary Interop Assembly (PIA) que acompanha o Visual Studio 2005

Dica do SistemaEste artigo aplica-se a um sistema operativo diferente do que está a utilizar. Foi desactivado o conteúdo do artigo, que pode não ser relevante para si.
cuidado ADO e ADO MD não foram totalmente testados em um ambiente Microsoft .NET Framework. Eles podem causar problemas intermitentes, especialmente em aplicativos baseados em serviço ou em aplicativos multissegmentados. As técnicas descritos neste artigo só devem ser usadas como uma medida temporária durante a migração para o ADO.NET. Você só deve usar essas técnicas depois de ter conduzido teste completo para verificar não se estão nenhum problema de compatibilidade. Quaisquer problemas que são causados por usando ADO ou ADO MD dessa maneira não são suportados. Para obter mais informações, consulte o seguinte artigo na Base de dados de Conhecimento da Microsoft:
840667   (http://support.microsoft.com/kb/840667/ ) Você receber erros inesperados ao usar o ADO e ADO MD em um aplicativo .NET Framework

Nesta página

Expandir tudo | Recolher tudo

INTRODUÇÃO

Este artigo descreve os problemas conhecidos para o ADODB Primary Interop Assembly (PIA) que acompanha o Microsoft Visual Studio 2005.

Mais Informações

Diferenças no coletor de lixo entre o Microsoft Visual Basic 6.0 e o Microsoft Visual Basic .NET

Existem diferenças principais entre coleta de lixo no Visual Basic 6.0 e no Visual Basic. NET. A principal diferença é que a coleta de lixo do Visual Basic 6.0 é mais agressiva de coleta de lixo .NET do Visual Basic. Com o Visual Basic 6.0, assim que uma instância de objeto fica fora do escopo, o objeto imediatamente é lançado. O mesmo comportamento não ocorre com o Visual Basic .NET ou com coleta de lixo .NET comum. Com coleta de lixo .NET, objetos são liberados assincronamente.

Essa diferença na coleta de lixo pode ter um grande efeito sobre o código de acesso a dados quando você move do Visual Basic 6.0 para Visual Basic. NET.

Por exemplo, um objeto ADODB Recordset aberto será fechado quando o objeto é recuperado pela coleta de lixo. Os desenvolvedores que têm experiência em escrever código do Visual Basic 6.0 podem depender de semântica de coleta de lixo que será alterado quando migrar o código para o Visual Basic .NET. Como coleta de lixo do .NET é assíncrona e não-determinística, você não pode ver as alterações mesmo após o teste básico ocorre.

Alguns bancos de dados, como bancos de dados Microsoft SQL Server 2000, somente oferecem suporte a um único resultado ativo definido por conexão. Se você tiver um cursor firehose abrir em uma conexão ao SQL Server, que conexão está bloqueada até que o cursor seja fechado. Por padrão, provedores de banco de dados OLE abrirá conexões adicionais para executar consultas se a conexão atual não é possível executar essa consulta. Portanto, muitos usuários de ActiveX Data Objects (ADO) são insensíveis a essa limitação. Essas conexões adicionais não participam pool de conexão. As tentativas para abrir conexões adicionais quando a conexão bloqueada está participando em uma transação falharão.

É recomendável que você revise seu código Visual Basic 6.0 e fechar explicitamente todos os objetos Recordset e conexões. Em seguida, testar novamente seu código depois de migrar seu código para Visual Basic. NET.

Esta seção lista três exemplos desse problema e exemplos de código para cada exemplo.

Exemplo 1: Abrir o conexões adicionais quando você não fechar explicitamente os objetos Recordset

Quando você executa o seguinte exemplo de código no Visual Basic 6.0, somente uma única conexão é necessária. Isso ocorre porque o objeto Recordset que criou no procedimento ExecuteQuery implicitamente está fechado quando o objeto Recordset fica fora do escopo. O exemplo de código usa a variável do SQL Server @@ SPID para representar o identificador de processo do servidor que é usado para executar a consulta. Se você executar o código, você irá notar que as consultas retornam o mesmo valor de @@ spid coluna. Esse resultado significa que as consultas foram executadas na mesma conexão ao banco de dados.
Public Sub Main()
    Dim strConn As String
    Dim cn As ADODB.Connection
    
    strConn = "Provider=SQLOLEDB;Data Source=.;" & _
              "Initial Catalog=Northwind;Trusted_Connection=Yes;"
    
    Set cn = New ADODB.Connection
    cn.Open strConn
    
    cn.Properties("Multiple Connections").Value = False
    
    ExecuteQuery cn, "SELECT @@spid, * FROM Customers"
    ExecuteQuery cn, "SELECT @@spid, * FROM Customers"
End Sub

Private Sub ExecuteQuery(cn As ADODB.Connection, strSQL As String)
    Dim rs As ADODB.Recordset
    Set rs = cn.Execute(strSQL)
    MsgBox rs(0)
End Sub
se você usar código semelhante no Visual Basic. NET, você irá notar que o segundo objeto Recordset contém um valor diferente para @@ spid coluna. Esse valor significa que a consulta foi executada em uma conexão diferente para o banco de dados.

Esse comportamento é diferente porque o objeto Recordset que foi criado no procedimento de ExecuteQuery não foi fechado e permanecerá aberto até que o coletor de lixo .NET limpa o objeto Recordset . Coleta de lixo no Microsoft .NET Framework ocorre de forma assíncrona. Se o objeto Recordset não foi fechado no momento em que o procedimento de ExecuteQuery é chamado novamente, o SQL Server provedor OLE DB abrirá uma nova conexão para executar a segunda consulta.

Se você adicionar uma chamada para o comando rs.Close no procedimento de ExecuteQuery , você Certifique-se que as consultas são executadas na mesma conexão. Você pode dizer também explicitamente o SQL Server provedor OLE DB não para abrir conexões adicionais. Para fazer isso, adicione a seguinte linha de código imediatamente após abrir a conexão:
cn.Properties("Multiple Connections").Value = False
este código faz com que o SQL Server provedor OLE DB lançar uma exceção sempre que o provedor OLE DB caso contrário, seria aberta conexões adicionais.

Exemplo 2: Problemas ocorrem quando você trabalha com transações se você não fechar explicitamente os objetos Recordset

Não é possível abrir conexões adicionais quando a conexão bloqueada está participando em uma transação. Quando você executa o seguinte exemplo de código no Visual Basic 6.0, o código executa várias consultas em uma única conexão que tenha uma transação aberta. O código chama duas funções a seguir:
  • GetCustomers
  • GetOrders
Cada função abre um objeto Recordset .
Public Sub Main()
    Dim cn As ADODB.Connection
    Set cn = New ADODB.Connection
    cn.Open "Provider=SQLOLEDB;Data Source=.;" & _
            "Initial Catalog=Northwind;Trusted_Connection=Yes;"
    
    cn.BeginTrans
    
    GetCustomers cn
    GetOrders cn
    
    cn.RollbackTrans
    cn.Close
End Sub

Public Sub GetCustomers(Connection As ADODB.Connection)
    Dim rs As ADODB.Recordset
    Set rs = Connection.Execute("SELECT CustomerID, CompanyName FROM Customers")
End Sub

Public Sub GetOrders(Connection As ADODB.Connection)
    Dim rs As ADODB.Recordset
    Set rs = Connection.Execute("SELECT OrderID, CustomerID FROM Orders")
End Sub
o objeto Recordset que é criado chamando a função GetCustomers implicitamente é fechado ao final dessa chamada de função no Visual Basic 6.0. Esse comportamento é descrito no "exemplo 1: abrir o conexões adicionais quando você não fechar explicitamente os objetos Recordset" seção. No entanto, esse objeto Recordset não pode ser fechado pelo tempo que seu código chama a função GetOrders no Visual Basic. NET. Portanto, a conexão atual para o SQL Server tem um resultado aberto com informações do cliente. Porque a conexão atual está ocupada, recuperar os resultados para a consulta na função GetOrders requer um novo criadas implicitamente a conexão. No entanto, não é possível criar uma conexão implícita, desde que uma transação seja aberta. Portanto, o código falhará, e você receberá a seguinte mensagem de erro:
Não é possível criar nova conexão porque no modo de transação manual ou distribuído.
Para resolver esse problema, feche explicitamente os objetos Recordset que foram criados usando as funções GetCustomers e GetOrders .

Exemplo 3: Problemas ocorrem quando você cria implicitamente e, em seguida, abandonar objetos Recordset

Por padrão, o método execute dos objetos de conexão e comando implicitamente cria e retorna um novo objeto Recordset . No Visual Basic 6.0, se esse objeto Recordset não é mantido em uma variável de objeto, o objeto Recordset fica fora do escopo e é fechado imediatamente. Portanto, o exemplo de código a seguir executa com êxito no Visual Basic 6.0. No entanto, você receberá a mensagem de erro mencionada no "exemplo 2: problemas ocorrem quando você trabalha com transações se você não fechar explicitamente os objetos Recordset" seção se o código for migrado para o Visual Basic .NET.
Dim cn As ADODB.Connection
Set cn = New ADODB.Connection
cn.Open "Provider=SQLOLEDB;Data Source=.;" & _
        "Initial Catalog=Northwind;Trusted_Connection=Yes;"

cn.BeginTrans

cn.Execute "SELECT CustomerID, CompanyName FROM Customers"
cn.Execute "SELECT OrderID, CustomerID FROM Orders ORDER BY CustomerID"

cn.RollbackTrans
cn.Close
neste exemplo de código, as chamadas para o método execute do objeto Connection implicitamente retornam objetos Recordset . Coleta de lixo no Visual Basic 6.0 fecha imediatamente cada objeto Recordset porque o valor de retorno não está armazenado em uma variável. Coleta de lixo não é agressiva como no Visual Basic. NET. O objeto Recordset que contém as informações do cliente é aberto quando ocorre a chamada para consultar o banco de dados para informações de ordem. Portanto, você receber a mensagem de erro mencionada no "exemplo 2: problemas ocorrem quando você trabalha com transações se você não fechar explicitamente os objetos Recordset" seção.

Para resolver esse problema, passe o valor adExecuteNoRecords do valor ExecuteOptionsEnum no parâmetro Opções do método execute . Quando você fizer isso, você pode indicar que o método execute não deve retornar um objeto Recordset conforme ilustrado no seguinte exemplo de código.
cn.Execute "SELECT CustomerID, CompanyName FROM Customers", , _
           ADODB.ExecuteOptionsEnum.adExecuteNoRecords

Problema 2: Não é recomendável o PIA ADODB para cenários de carga

É altamente desencorajar você de usar o PIA ADODB em cenários de carga, como em componentes do Microsoft ASP.NET ou o Microsoft COM + multiusuário. Quando as equipes de teste da Microsoft testado o PIA ADODB, as equipes de teste localizado que o PIA ADODB falhar sob carga excessiva. Se o código de acesso de dados .NET deve executar confiável sob carga excessiva, é altamente recomendável que você escrever o código usando o ADO.NET.

Problema 3: Não é recomendável que você usar o PIA ADODB no modo de 64 bits

É altamente desencorajar você de usar o PIA ADODB em aplicativos de 64 bits. O PIA ADODB não foram testado no modo de 64 bits. A maioria dos cenários de 64-bit envolvem componentes do lado do servidor de alto-estresse, tais como ASP.NET ou COM +. O PIA ADODB tem conhecidos problemas ao executar sob carga excessiva. A disponibilidade limitada de provedores OLE DB de 64 bits também torna o modo de 64 bits menos interessantes para trabalhar com o PIA ADODB.

Problema 4: Falhas ocorrem quando você usar execução de consulta de ligação tardia

ADODB oferece suporte a dois formulários de execução de consulta de ligação tardia. Execução de consulta de ligação tardia permite usar a ligação de IDispatch em COM para executar consultas como se as consultas foram métodos em um objeto Connection . ADODB oferece suporte a duas seguintes formas de execução de consulta de ligação tardia:
  • Crie uma consulta "nomeada" definindo a propriedade nome do objeto Command .
  • Execute uma chamada de procedimento armazenado.
Você pode ter problemas com esses formulários ao migrar o código do Visual Basic 6.0 para Visual Basic. NET.

Os exemplos a seguintes ilustram esses problemas.

Exemplo 1: Se você criar uma segunda consulta de ligação tardia que tem o mesmo nome, a consulta falhar

O exemplo de código a seguir cria duas consultas de ligação tardia que usam o mesmo valor para a propriedade Name do objeto Command .
Dim cn As ADODB.Connection
Dim cmd As ADODB.Command
Dim rs As ADODB.Recordset
Dim strConn As String
    
'Open a new Connection.
strConn = "Provider=SQLOLEDB;Data Source=.;" & _
          "Initial Catalog=Northwind;Trusted_Connection=Yes"
Set cn = New ADODB.Connection
cn.Open strConn
    
'Create a Command object, and then set the Name property 
'to enable the Command object as a late-bound method call.
Set cmd = New ADODB.Command
cmd.CommandText = "SELECT COUNT(*) FROM Customers"
cmd.Name = "GetCount"
Set cmd.ActiveConnection = cn
    
'Execute the Command object as a late-bound method call on the Connection.
Set rs = New ADODB.Recordset
cn.GetCount rs
Debug.Print rs(0).Value
rs.Close
Set rs = Nothing
    
'Release the Command object.
Set cmd = Nothing
    
'Create a new Command object, and then set the Name property
'to enable the Command object as a late-bound method call.
Set cmd = New ADODB.Command
cmd.CommandText = "SELECT COUNT(*) FROM Orders"
cmd.Name = "GetCount"
Set cmd.ActiveConnection = cn
    
'Execute the Command object as a late-bound method call on the Connection object.
Set rs = New ADODB.Recordset
cn.GetCount rs
Debug.Print rs(0).Value
rs.Close
Set rs = Nothing
    
'Clean up.
cn.Close
no Visual Basic 6.0, assim que o objeto Command é definido como Nothing, o objeto é recuperado pela coleta de lixo. O objeto Connection é notificado que o objeto de comando foi destruído. Portanto, quando o segundo objeto de comando está associado ao objeto Connection , nenhum conflito.

Quando o código semelhante é executado no Visual Basic. NET, o objeto de comando pode não recuperado pela coleta de lixo pelo tempo que o segundo objeto de comando está associado com o objeto Connection . Portanto, você receberá a seguinte mensagem de erro exceção:
Objeto já está na coleção. Não é possível acrescentar.
Para resolver esse problema, manualmente, desassocie o primeiro comando objeto do objeto de conexão . Para fazer isso, chame explicitamente o método cmd.ActiveConnection quando você limpar o objeto de comando . Para fazer isso, use o exemplo de código seguinte.
'Visual Basic 6.0 syntax
Set cmd.ActiveConnection = Nothing

'Visual Basic .NET syntax
cmd.ActiveConnection = Nothing

Exemplo 2: Se você chamar uma consulta de ligação tardia em uma segunda conexão, a consulta falhará

O exemplo de código a seguir executa as seguintes tarefas na ordem em que eles são apresentados:
  1. Crie dois objetos de conexão .
  2. Crie um objeto de comando em cada objeto de conexão . Cada objeto de comando tem o mesmo valor para a propriedade Name .
  3. Execute cada comando usando a execução de consulta de ligação tardia.
Dim strConn As String, strSQL As String
Dim cn1 As ADODB.Connection, cn2 As ADODB.Connection
Dim cmd1 As ADODB.Command, cmd2 As ADODB.Command
Dim rs1 As ADODB.Recordset, rs2 As ADODB.Recordset
    
strConn = "Provider=SQLOLEDB;Data Source=.;" & _
          "Initial Catalog=Northwind;Trusted_Connection=Yes;"
strSQL = "SELECT COUNT(*) FROM Customers"
    
'Open connections.
Set cn1 = New ADODB.Connection
Set cn2 = New ADODB.Connection
cn1.Open strConn
cn2.Open strConn
    
'Create commands so that the commands can be executed as late-bound methods.
Set cmd1 = New ADODB.Command
Set cmd2 = New ADODB.Command
cmd1.CommandText = strSQL
cmd2.CommandText = strSQL
cmd1.Name = "GetCount"
cmd2.Name = "GetCount"
Set cmd1.ActiveConnection = cn1
Set cmd2.ActiveConnection = cn2
    
'Execute queries as late-bound methods.
Set rs1 = New ADODB.Recordset
Set rs2 = New ADODB.Recordset
cn1.GetCount rs1
cn2.GetCount rs2
MsgBox rs1(0).Value
MsgBox rs2(0).Value
    
'Clean up.
rs1.Close
rs2.Close
cn1.Close
cn2.Close
Este exemplo de código tiver êxito ao usar o Visual Basic 6.0. No entanto, este exemplo de código falha quando você usar o Visual Basic. NET. Esta falha ocorre por causa das seguintes razões:
  • Como o ADODB prepara essas consultas como métodos de ligação tardia
  • Suposições que o compilador do Visual Basic .NET faz sobre esses métodos
Quando você definir a propriedade ActiveConnection do objeto Command , ADODB verifica se o objeto de comando com a propriedade nome definida. Se a propriedade Name for definida, ADODB prepara a consulta para que a consulta pode ser executada como um método tardia no objeto Connection . Neste exemplo, dois objetos de comando tem o mesmo valor para a propriedade CommandText . No entanto, isso é um exemplo muito simples. Embora os objetos de comando tiverem o mesmo valor para a propriedade Name , os objetos de comando podem ter valores CommandText que executaria consultas muito diferentes. Portanto, ADODB gera assinaturas de método exclusivo para os métodos de ligação tardia.

O compilador do Visual Basic .NET não faz essa diferenciação. Na primeira chamada para a consulta "GetCount", o compilador do Visual Basic .NET armazena a assinatura do método no caso de outra chamada é feita para um método GetCount em um objeto Connection . Quando o código chama a segunda consulta "GetCount", o Visual Basic .NET reutiliza a assinatura de método em cache para o segundo método GetCount . Como ADODB gera assinaturas de método exclusivo, a segunda consulta de ligação tardia chamada falhará.

Não há solução existe para esse cenário.

Problema 5: Você pode definir alguns tipos de dados Variant ADODB a seqüência tipos de dados

O modelo de objeto ADODB permite que você defina algumas propriedades com seqüências de caracteres ou a outros objetos ADODB. Por exemplo, a propriedade ActiveConnection do objeto Recordset aparece no Pesquisador de objeto Visual Basic 6.0 como um tipo de dados Variant e pode ser definida como um objeto Connection ou uma seqüência de conexão.

Se você tiver criado seu próprio objeto e deseja oferecer suporte a essa funcionalidade, você deve criar acessadores de propriedade separado. Para fazer isso, use o código que é semelhante ao exemplo de código a seguir.
Public Property Let ActiveConnection (ByVal value As String)
    'Add logic here.
End Property

Public Property Set ActiveConnection (ByRef value As Object)
    'Add logic here.
End Property
o .NET Framework é um pouco mais rígido e não permite que vários acessadores de propriedade com diferentes tipos de dados. O PIA ADODB permite que você defina a propriedade ActiveConnection do objeto Recordset como um objeto Connection . Se você deseja definir a propriedade ActiveConnection como uma seqüência de caracteres, você deve usar o método let_ActiveConnection conforme o exemplo de código a seguir.
Dim strConn As String
Dim rs As ADODB.Recordset
    
strConn = "Provider=SQLOLEDB;Data Source=.;" & _
          "Initial Catalog=Northwind;Trusted_Connection=Yes;"
rs = New ADODB.Recordset
rs.let_ActiveConnection(strConn)
a mesma abordagem é necessária quando você define as propriedades a seguir:
  • A propriedade fonte do objeto Recordset
  • A propriedade ActiveConnection do objeto Command
Essas propriedades aceitam objetos. Para definir essas propriedades com seqüências de caracteres, você deve usar o método let_ MethodName correspondente.

: 6 Uma exceção InvalidCastException ocorre quando você chamar o método Parameters.Append

O PIA de ADODB está incluído no Microsoft Visual Studio .NET 2003 e no Visual Studio 2005 tem um problema conhecido que ocorre quando você chamar o método Parameters.Append juntamente com um objeto de parâmetro que foi criado usando o construtor padrão.

O exemplo de código a seguir causará uma exceção InvalidCastException . cmd
Dim cmd As ADODB.Command
Dim p As ADODB.Parameter

cmd = New ADODB.Command
cmd.CommandText = "SELECT CustomerID FROM Orders WHERE OrderID = ?"

p = New ADODB.Parameter
p.Name = "@OrderID"
p.Type = ADODB.DataTypeEnum.adInteger
p.Value = 10248

cmd.Parameters.Append(p)

para contornar esse problema, criar os objetos de parâmetro usando o método CreateParameter do objeto Command , conforme ilustrado pelo seguinte exemplo de código. cmd
Dim cmd As ADODB.Command
Dim p As ADODB.Parameter

cmd = New ADODB.Command
cmd.CommandText = "SELECT CustomerID FROM Orders WHERE OrderID = ?"

p = cmd.CreateParameter()
p.Name = "@OrderID"
p.Type = ADODB.DataTypeEnum.adInteger
p.Value = 10248

cmd.Parameters.Append(p)

Problema 7: Você enfrentar problemas de trabalhar com componentes que esperam ADO 2.8 interfaces

O PIA ADODB que acompanha o Visual Studio 2005 é o mesmo componente que foi incluído no Visual Studio .NET 2003 e foi criado usando o Microsoft .NET Framework 1.1. O PIA ADODB foi criado para interagir com o ADO 2.7 interfaces e não tiver sido atualizado para trabalhar com ADO 2.8 interfaces.

Portanto, tentativas para usar o PIA ADODB juntamente com componentes que expõem ADO 2,8 interfaces será falhar. Não há suporte para esse cenário com o PIA ADODB.

A informação contida neste artigo aplica-se a:
  • Microsoft Visual Studio 2005 Professional Edition
  • Microsoft Visual Studio 2005 Standard Edition
  • Microsoft Visual Studio 2005 Team System Architect Edition
  • Microsoft Visual Studio 2005 Team System Developer Edition
  • Microsoft Visual Studio 2005 Team System Team Foundation:
  • Microsoft Visual Studio 2005 Team System Test Edition
  • Microsoft Visual Studio 2005 Express Edition
Palavras-chave: 
kbmt kbinfo KB910696 KbMtpt
Tradução automáticaTradução automática
IMPORTANTE: Este artigo foi traduzido por um sistema de tradução automática (também designado por Machine Translation ou MT), não tendo sido portanto traduzido ou revisto por pessoas. A Microsoft possui artigos traduzidos por aplicações (MT) e artigos traduzidos por tradutores profissionais, com o objetivo de oferecer em português a totalidade dos artigos existentes na base de dados de suporte. No entanto, a tradução automática não é sempre perfeita, podendo conter erros de vocabulário, sintaxe ou gramática. A Microsoft não é responsável por incoerências, erros ou prejuízos ocorridos em decorrência da utilização dos artigos MT por parte dos nossos clientes. A Microsoft realiza atualizações freqüentes ao software de tradução automática (MT). Obrigado.
Clique aqui para ver a versão em Inglês deste artigo: 910696  (http://support.microsoft.com/kb/910696/en-us/ )