Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
por Scott Mitchell
Os TableAdapters dentro de um Conjunto de Dados Tipado tratam automaticamente da ligação à base de dados, emitindo comandos e preenchendo uma Tabela de Dados com os resultados. No entanto, há ocasiões em que queremos cuidar desses detalhes nós mesmos, e neste tutorial aprendemos como acessar as configurações de nível de conexão e comando do banco de dados no TableAdapter.
Ao longo da série de tutoriais, usamos Typed DataSets para implementar a camada de acesso a dados e objetos empresariais da nossa arquitetura em camadas. Conforme discutido no primeiro tutorial, as DataTables do Typed DataSet servem como repositórios de dados, enquanto os TableAdapters atuam como wrappers para se comunicar com o banco de dados para recuperar e modificar os dados subjacentes. Os TableAdapters encapsulam a complexidade envolvida no trabalho com o banco de dados e nos poupam de ter que escrever código para nos conectar ao banco de dados, emitir um comando ou preencher os resultados em uma DataTable.
Há momentos, no entanto, em que precisamos escavar nas profundezas do TableAdapter e escrever código que funciona diretamente com os objetos ADO.NET. No tutorial Encapsulando modificações de banco de dados em uma transação , por exemplo, adicionamos métodos ao TableAdapter para iniciar, confirmar e reverter ADO.NET transações. Esses métodos usaram um objeto interno criado SqlTransaction
manualmente que foi atribuído aos objetos TableAdapter s SqlCommand
.
Neste tutorial, examinaremos como acessar as configurações de nível de conexão e comando do banco de dados no TableAdapter. Em particular, adicionaremos funcionalidade ao ProductsTableAdapter
que permite o acesso à cadeia de conexão subjacente e às configurações de tempo limite do comando.
O Microsoft .NET Framework contém uma infinidade de classes projetadas especificamente para trabalhar com dados. Essas classes, encontradas dentro do System.Data
namespace, são chamadas de classes ADO.NET . Algumas das classes sob o guarda-chuva ADO.NET estão vinculadas a um provedor de dados específico. Você pode pensar em um provedor de dados como um canal de comunicação que permite que as informações fluam entre as classes ADO.NET e o armazenamento de dados subjacente. Existem provedores generalizados, como OleDb e ODBC, bem como provedores que são especialmente projetados para um sistema de banco de dados específico. Por exemplo, embora seja possível se conectar a um banco de dados do Microsoft SQL Server usando o provedor OleDb, o provedor SqlClient é muito mais eficiente, pois foi projetado e otimizado especificamente para o SQL Server.
Ao acessar dados programaticamente, o seguinte padrão é comumente usado:
- Estabeleça uma conexão com o banco de dados.
- Emita um comando.
- Para consultas
SELECT
, utilize os registos resultantes.
Há classes ADO.NET separadas para executar cada uma dessas etapas. Para se conectar a um banco de dados usando o provedor SqlClient, por exemplo, use a SqlConnection
classe. Para emitir um INSERT
comando , UPDATE
, DELETE
, ou SELECT
para o banco de dados, use a SqlCommand
classe.
Exceto para o tutorial Encapsulando modificações de banco de dados em um tutorial de transação , não tivemos que escrever nenhum código de ADO.NET de baixo nível porque o código gerado automaticamente por TableAdapters inclui a funcionalidade necessária para se conectar ao banco de dados, emitir comandos, recuperar dados e preencher esses dados em DataTables. No entanto, pode haver momentos em que precisamos personalizar essas configurações de baixo nível. Nas próximas etapas, examinaremos como aproveitar os objetos ADO.NET usados internamente pelos TableAdapters.
Cada classe TableAdapter tem uma Connection
propriedade que especifica informações de conexão de banco de dados. O tipo de dados e ConnectionString
valor dessa propriedade são determinados pelas seleções feitas no assistente de Configuração do TableAdapter. Lembre-se de que, quando adicionamos pela primeira vez um TableAdapter a um DataSet Typed, esse assistente nos solicita a fonte do banco de dados (consulte a Figura 1). A lista suspensa nesta primeira etapa inclui os bancos de dados especificados no arquivo de configuração, bem como quaisquer outros bancos de dados nas ligações de dados do Explorador de Servidores. Se o banco de dados que queremos usar não existir na lista suspensa, uma nova conexão de banco de dados pode ser especificada clicando no botão Nova conexão e fornecendo as informações de conexão necessárias.
Figura 1: A primeira etapa do Assistente de configuração do TableAdapter (Clique para visualizar a imagem em tamanho real)
Vamos dar um momento para inspecionar o código para a propriedade Connection
do TableAdapter. Conforme observado no tutorial Criando uma camada de acesso a dados , podemos exibir o código TableAdapter gerado automaticamente indo para a janela Exibição de classe, detalhando para a classe apropriada e, em seguida, clicando duas vezes no nome do membro.
Navegue até a janela Modo de Exibição de Classe acessando o menu Exibir e escolhendo Modo de Exibição de Classe (ou digitando Ctrl+Shift+C). Na metade superior da janela Class View, faça drill down até o NorthwindTableAdapters
namespace e selecione a ProductsTableAdapter
classe. Isso exibirá os membros ProductsTableAdapter
na metade inferior da Visualização de Classe, como mostra a Figura 2. Clique duas vezes na Connection
propriedade para ver seu código.
Figura 2: Double-Click a propriedade Connection na visualização Class para exibir seu código gerado automaticamente
A propriedade Connection
do TableAdapter e outro código relacionado à conexão segue:
private System.Data.SqlClient.SqlConnection _connection;
private void InitConnection() {
this._connection = new System.Data.SqlClient.SqlConnection();
this._connection.ConnectionString =
ConfigurationManager.ConnectionStrings["NORTHWNDConnectionString"].ConnectionString;
}
internal System.Data.SqlClient.SqlConnection Connection {
get {
if ((this._connection == null)) {
this.InitConnection();
}
return this._connection;
}
set {
this._connection = value;
if ((this.Adapter.InsertCommand != null)) {
this.Adapter.InsertCommand.Connection = value;
}
if ((this.Adapter.DeleteCommand != null)) {
this.Adapter.DeleteCommand.Connection = value;
}
if ((this.Adapter.UpdateCommand != null)) {
this.Adapter.UpdateCommand.Connection = value;
}
for (int i = 0; (i < this.CommandCollection.Length); i = (i + 1)) {
if ((this.CommandCollection[i] != null)) {
((System.Data.SqlClient.SqlCommand)
(this.CommandCollection[i])).Connection = value;
}
}
}
}
Quando a classe TableAdapter é instanciada, a variável _connection
membro é igual a null
. Quando a Connection
propriedade é acessada, ela primeiro verifica se a _connection
variável membro foi instanciada. Se não tiver, o método InitConnection
é invocado, que instancia _connection
e define a sua propriedade ConnectionString
para o valor da string de conexão especificado na primeira etapa do assistente de Configuração de TableAdapter.
A Connection
propriedade também pode ser atribuída a um SqlConnection
objeto. Isso associa o novo SqlConnection
objeto a cada um dos objetos TableAdapter SqlCommand
.
As informações de conexão devem permanecer encapsuladas dentro do TableAdapter e não devem ser acessíveis a outras camadas na arquitetura do aplicativo. No entanto, pode haver cenários em que as informações de nível de conexão do TableAdapter precisam ser acessíveis ou personalizáveis para uma consulta, usuário ou página ASP.NET.
Vamos estender o ProductsTableAdapter
no Northwind
DataSet para incluir uma ConnectionString
propriedade que pode ser usada pela Business Logic Layer para ler ou alterar a cadeia de conexão usada pelo TableAdapter.
Nota
Uma cadeia de conexão é uma cadeia de caracteres que especifica informações de conexão do banco de dados, como o provedor a ser usado, o local do banco de dados, credenciais de autenticação e outras configurações relacionadas ao banco de dados. Para obter uma lista de padrões de cadeia de conexão usados por uma variedade de armazenamentos de dados e provedores, consulte ConnectionStrings.com.
Conforme discutido no tutorial Criando uma camada de acesso a dados , as classes geradas automaticamente pelo conjunto de dados digitado podem ser estendidas por meio do uso de classes parciais. Primeiro, crie uma nova subpasta no projeto nomeado ConnectionAndCommandSettings
abaixo da ~/App_Code/DAL
pasta.
Figura 3: Adicionar uma subpasta chamada ConnectionAndCommandSettings
Adicione um novo arquivo de classe chamado ProductsTableAdapter.ConnectionAndCommandSettings.cs
e digite o seguinte código:
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
namespace NorthwindTableAdapters
{
public partial class ProductsTableAdapter
{
public string ConnectionString
{
get
{
return this.Connection.ConnectionString;
}
set
{
this.Connection.ConnectionString = value;
}
}
}
}
Essa classe parcial adiciona uma public
propriedade nomeada ConnectionString
à ProductsTableAdapter
classe que permite que qualquer camada leia ou atualize a cadeia de conexão para a conexão subjacente do TableAdapter.
Com essa classe parcial criada (e salva), abra a ProductsBLL
classe. Vá para uma das métodos existentes e digite Adapter
e, em seguida, pressione a tecla de ponto para abrir o IntelliSense. Você deve ver a nova ConnectionString
propriedade disponível no IntelliSense, o que significa que você pode ler ou ajustar programaticamente esse valor a partir da BLL.
Essa classe parcial expõe apenas uma propriedade do objeto de conexão subjacente: ConnectionString
. Se você quiser tornar todo o objeto de conexão disponível além dos limites do TableAdapter, você pode, alternativamente, alterar o Connection
nível de proteção da propriedade. O código gerado automaticamente que examinamos na Etapa 1 mostrou que a propriedade s de Connection
TableAdapter está marcada como internal
, o que significa que ela só pode ser acessada por classes no mesmo assembly. Isso, no entanto, pode ser alterado por meio da propriedade TableAdapter ConnectionModifier
.
Abra o Northwind
DataSet, clique no ProductsTableAdapter
no Designer e navegue até a janela Propriedades. Ali você verá o ConnectionModifier
definido ao seu valor padrão, Assembly
. Para tornar a propriedade Connection
disponível fora do assembly do Typed DataSet, altere a propriedade ConnectionModifier
para Public
.
Figura 4: O Connection
nível de acessibilidade da Propriedade pode ser configurado por meio da ConnectionModifier
Propriedade (Clique para visualizar a imagem em tamanho real)
Salve o DataSet e retorne à ProductsBLL
classe. Como antes, vá para um dos métodos existentes e digite Adapter
e, em seguida, pressione a tecla ponto para abrir o IntelliSense. A lista deve incluir uma Connection
propriedade, o que significa que agora você pode ler ou atribuir programaticamente quaisquer configurações de nível de conexão da BLL.
Um TableAdapter consiste numa consulta principal que, por padrão, tem instruções INSERT
, UPDATE
e DELETE
geradas automaticamente. Esta instrução principal, as INSERT
, UPDATE
e DELETE
instruções são incorporadas no código do TableAdapter como um objeto adaptador de dados ADO.NET através da propriedade Adapter
. Tal como acontece com a sua Connection
propriedade, o Adapter
tipo de dados da propriedade é determinado pelo fornecedor de dados utilizado. Como esses tutoriais usam o provedor SqlClient, a Adapter
propriedade é do tipo SqlDataAdapter
.
A propriedade TableAdapter s Adapter
tem três propriedades do tipo SqlCommand
que usa para emitir instruções INSERT
, UPDATE
e DELETE
.
InsertCommand
UpdateCommand
DeleteCommand
Um SqlCommand
objeto é responsável por enviar uma consulta específica para o banco de dados e tem propriedades como: CommandText
, que contém a instrução SQL ad-hoc ou o procedimento armazenado a ser executado, e Parameters
, que é uma coleção de SqlParameter
objetos. Como vimos no tutorial Criando uma camada de acesso a dados , esses objetos de comando podem ser personalizados por meio da janela Propriedades.
Além de sua consulta principal, o TableAdapter pode incluir um número variável de métodos que, quando invocados, despacham um comando especificado para o banco de dados. O objeto de comando s da consulta principal e os objetos de comando para todos os métodos adicionais são armazenados na propriedade s CommandCollection
de TableAdapter.
Vamos dar um momento para olhar o código gerado pelo ProductsTableAdapter
no Northwind
DataSet para essas duas propriedades e suas variáveis de membro de suporte e métodos auxiliares:
private System.Data.SqlClient.SqlDataAdapter _adapter;
private void InitAdapter() {
this._adapter = new System.Data.SqlClient.SqlDataAdapter();
... Code that creates the InsertCommand, UpdateCommand, ...
... and DeleteCommand instances - omitted for brevity ...
}
private System.Data.SqlClient.SqlDataAdapter Adapter {
get {
if ((this._adapter == null)) {
this.InitAdapter();
}
return this._adapter;
}
}
private System.Data.SqlClient.SqlCommand[] _commandCollection;
private void InitCommandCollection() {
this._commandCollection = new System.Data.SqlClient.SqlCommand[9];
... Code that creates the command objects for the main query and the ...
... ProductsTableAdapter�s other eight methods - omitted for brevity ...
}
protected System.Data.SqlClient.SqlCommand[] CommandCollection {
get {
if ((this._commandCollection == null)) {
this.InitCommandCollection();
}
return this._commandCollection;
}
}
O código para as propriedades Adapter
e CommandCollection
replica de perto o da propriedade Connection
. Há variáveis de membro que contêm os objetos usados pelas propriedades. Os acessadores de propriedades get
começam verificando se a variável membro correspondente é null
. Em caso afirmativo, um método de inicialização é chamado que cria uma instância da variável membro e atribui as propriedades relacionadas ao comando principal.
Idealmente, as informações de nível de comando devem permanecer encapsuladas dentro da Camada de Acesso a Dados. Se essas informações forem necessárias em outras camadas da arquitetura, no entanto, elas podem ser expostas por meio de uma classe parcial, assim como nas configurações de nível de conexão.
Como o TableAdapter tem apenas uma única Connection
propriedade, o código para expor as configurações de nível de conexão é bastante simples. As coisas são um pouco mais complicadas ao modificar configurações de nível de comando porque o TableAdapter pode ter vários objetos de comando - um InsertCommand
, UpdateCommand
e DeleteCommand
, juntamente com um número variável de objetos de comando na CommandCollection
propriedade. Ao atualizar as configurações de nível de comando, essas configurações precisarão ser propagadas para todos os objetos de comando.
Por exemplo, imagine que havia certas consultas no TableAdapter que levaram um tempo extraordinário para serem executadas. Ao usar o TableAdapter para executar uma dessas consultas, talvez queiramos aumentar a propriedade s CommandTimeout
do objeto de comando. Esta propriedade especifica o número de segundos a aguardar a execução do comando e assume como padrão 30.
Para permitir que a CommandTimeout
propriedade seja ajustada pela BLL, adicione o seguinte public
método ao ProductsDataTable
usando o arquivo de classe parcial criado na Etapa 2 (ProductsTableAdapter.ConnectionAndCommandSettings.cs
):
public void SetCommandTimeout(int timeout)
{
if (this.Adapter.InsertCommand != null)
this.Adapter.InsertCommand.CommandTimeout = timeout;
if (this.Adapter.DeleteCommand != null)
this.Adapter.DeleteCommand.CommandTimeout = timeout;
if (this.Adapter.UpdateCommand != null)
this.Adapter.UpdateCommand.CommandTimeout = timeout;
for (int i = 0; i < this.CommandCollection.Length; i++)
if (this.CommandCollection[i] != null)
this.CommandCollection[i].CommandTimeout = timeout;
}
Esse método pode ser invocado a partir da BLL ou da Camada de Apresentação para definir o tempo limite do comando para todos os comandos emitidos por essa instância de TableAdapter.
Nota
As Adapter
propriedades e CommandCollection
são marcadas como private
, o que significa que elas só podem ser acessadas a partir do código dentro do TableAdapter. Ao contrário da Connection
propriedade, esses modificadores de acesso não são configuráveis. Portanto, se você precisar expor propriedades de nível de comando para outras camadas na arquitetura, deverá usar a abordagem de classe parcial discutida acima para fornecer um public
método ou propriedade que leia ou grave nos private
objetos de comando.
Os TableAdapters dentro de um DataSet Tipado servem para encapsular detalhes e complexidade de acesso a dados. Usando TableAdapters, não precisamos nos preocupar em escrever ADO.NET código para se conectar ao banco de dados, emitir um comando ou preencher os resultados em uma DataTable. Tudo é tratado automaticamente para nós.
No entanto, pode haver momentos em que precisamos personalizar as especificidades do ADO.NET de baixo nível, como alterar a cadeia de conexão ou os valores padrão de tempo limite de conexão ou comando. O TableAdapter gerou automaticamente as propriedades Connection
, Adapter
e CommandCollection
, mas estas são, por defeito, ou internal
ou private
. Essas informações internas podem ser expostas estendendo o TableAdapter usando classes parciais para incluir public
métodos ou propriedades. Como alternativa, o modificador de acesso da propriedade do TableAdapter Connection
pode ser configurado por meio da propriedade do TableAdapter ConnectionModifier
.
Feliz Programação!
Scott Mitchell, autor de sete livros sobre ASP/ASP.NET e fundador da 4GuysFromRolla.com, trabalha com tecnologias Web da Microsoft desde 1998. Scott trabalha como consultor, formador e escritor independente. Seu último livro é Sams Teach Yourself ASP.NET 2.0 in 24 Hours. Ele pode ser contatado em mitchell@4GuysFromRolla.com.
Esta série de tutoriais foi revisada por muitos revisores úteis. Os principais revisores deste tutorial foram Burnadette Leigh, S ren Jacob Lauritsen, Teresa Murphy e Hilton Geisenow. Interessado em rever meus próximos artigos do MSDN? Se for o caso, envie-me uma mensagem para mitchell@4GuysFromRolla.com.