Download
Todos os cdigos-fonte deste curso podem ser obtidos em cc.borland.com/
ccweb.exe/author?authorid=222668
1. Introduo
Este curso mostrar como utilizar os componentes do ADO.NET e BDP
para acesso a banco de dados usando o Delphi 8. Nesta primeira parte, faremos uma introduo ao ADO.NET, mostrando seus objetivos, arquitetura e
principais componentes. Depois, veremos na prtica como utilizar cada um dos
componentes do ADO.NET e BDP no Delphi 8, em aplicaes Windows Forms,
Web Forms e Web Services. Os exemplos que mostrarei neste curso so semelhantes ao que apresentei durante minha palestra na III Borland Conference.
O cdigo-fonte pode ser baixado no endereo cc.borland.com/cc/ccweb.exe/
author?authorid=222668.
Introduo ao ADO.NET
O ADO.NET a tecnologia de acesso a dados no .NET Framework. Sua
arquitetura elegante e bem definida oferece inmeros benefcios:
Interoperabilidade, Escalabilidade, Produtividade e Performance. O ADO.NET
uma evoluo do ADO (Active Data Objects) e totalmente escrito com
cdigo gerenciado (Managed Code). O ADO.NET uma evoluo do modelo
cliente/servidor, projetada especialmente para a construo de aplicaes
escalveis, distribudas e para Web.
Costumo dizer que o ADO.NET possui muitas caractersticas que a Borland
j havia incorporado tecnologia DataSnap. De fato, ambos os frameworks
foram construdos para suportar os mesmos tipos de aplicao. Com isso, se
voc j est acostumado a desenvolver aplicaes DataSnap ou mesmo client /
server (com dbExpress / DataSetProvider / ClientDataSet) no Delphi, no ter
maiores dificuldades em se adaptar ao novo modelo.
ClubeDelphi Curso de acesso a dados no Delphi 2005 ADO.NET e BDP
Guinther Pauli DevMedia - guinther@clubedelphi.net www.clubedelphi.net
Todos os direitos reservados
.1
Importante
Nenhuma parte deste curso,
sem autorizao prvia por
escrito do autor e da editora,
poder ser reproduzida, copiada ou transmitida, sejam
quais forem os meios empregados: eletrnicos, fotogrficos, gravao ou quaisquer
outros. Todos os direitos reservados e protegidos pela lei
5.988 de 14/12/73.h
Componentes do ADO.NET
As classes do ADO.NET esto divididas em dois grandes grupos: Managed
Provides (provedores gerenciados) e Content Components (componentes de
contedo).
Os componentes do grupo Managed Providers so responsveis pelo Acesso
a Dados, e incluem classes para conexo, transaes, execuo de comandos
e leitura de dados. O segundo grupo engloba os componentes que manipulam
os dados em memria, como DataSet, DataTable, DataRow, DataColumn etc.
No ADO.NET, os Providers so responsveis pelo acesso a dados. Um
Provider um conjunto de componentes que implementam as interfaces bsicas do ADO.NET, a saber:
IDbConnection - define mtodos e propriedades para conexo a uma fonte
de dados;
IDbDataAdapter - define mtodos e propriedades para obteno e atualizaes de dados;
.2
.3
Neste curso daremos especial ateno ao BDP. Mas lembre-se, como todos os Providers seguem o mesmo padro (implementam as mesmas interfaces),
a maioria das tcnicas que mostrarei neste curso usando o BDP podem ser
facilmente adaptadas a outros Providers. Ou seja, quando for apresentado um
recurso do BdpCommand, por exemplo, saiba que o mesmo pode ser utilizado
com o OracleCommand, SqlCommand, OleDbCommand etc. claro, o BDP
possui algumas exclusividades, que indicarei no texto quando a mesma no
estiver presente nos demais Providers.
O segundo grupo de componentes do ADO.NET so responsveis pela
cache e manipulao de dados na aplicao cliente. O principal componente
desse grupo (e diria da arquitetura do ADO.NET como um todo) o DataSet,
que uma coleo de objetos DataTable, algo semelhante ao ClientDataSet
para quem usa a VCL. O DataSet independe da fonte de dados, e pode ser
utilizado com qualquer um dos Providers listados anteriormente (o que tambm
se assemelha ao ClientDataSet da VCL, que pode ser usado como o dbExpress,
BDE, ADO, IBX etc). Faremos muitos exemplos demonstrando tcnicas avanadas do uso deste componente, e o estudaremos em detalhes futuramente.
Arquitetura
.4
.5
Nota Lembre-se que nosso foco principal a utilizao dos componentes do
BDP, porm, a maioria das
tcnicas apresentadas pode
ser facilmente aplicada aos
demais providers.
S Q L M a na g e d
S qlC o nnectio n
S Q lC o mmand
S qlD ataRead er
S q lD ataA d ap ter
Bd p Transactio n
S qlTransactio n
D a ta S e t
VC L
dbE x pre s s
S q lC o nnectio n
* IS Q LC o mmnand
S Q LD ataS et
S Q LD ataS et +
D ataS etP ro vid er
Transa es gerenciad as
pelo S Q LC onnectio n
BDE
D ataB ase
Q uery
Q uery +
D ataS etP r
Transa e
gerenciad a
C o le o de v rio s C lie ntD a ta S e
Dica O componente
BdpConnection do BDP
equivale aos seguintes da
VCL:
Database (para quem usa
BDE)
SQLConnection (dbExpress)
ADOConnection (ADO)
IBConnection (IBX)
.6
.7
Um exemplo prtico
Clique em File|New|Windows Forms Application. Arraste at o formulrio o
componente BdpConnection da categoria Borland Data Provider. Observe que
em uma aplicao Windows Forms os componentes no-visuais so
posicionados abaixo do designer.
Selecione o BdpConnection1 e no Object Inspector escolha EMPLOYEE
na propriedade ConnectionString:
.8
Dica: se voc arrastar a conexo Employee do Data
Explorer at o formulrio,
ser criado automaticamente
um BdpConnection, j configurado.
.9
Q
uando o estado de uma conexo muda, o evento StateChange do
BdpConnection disparado. Insira um manipulador para este evento e digite o
seguinte:
procedure TWinForm1.BdpConnection1_StateChange(
sender: System.Object; e: System.Data.StateChangeEventArgs);
begin
case BdpConnection1.State of
ConnectionState.Open : StatusBar1.Text := Connected to + BdpConnection1.Database;
ConnectionState.Closed : StatusBar1.Text := Disconnected;
end;
end;
Uma situao bastante comum voc ter que alterar os parmetros de conexo em tempo de execuo, quando sua aplicao for distribuda. Isso pode
acontecer devido ao caminho do banco de dados ser diferente quele configurado durante a fase de desenvolvimento, por exemplo. Poderamos inserir cdigo para ler em tempo de execuo as entradas do arquivo bdpconnections.xml,
e distribuir esse arquivo junto com a aplicao. O problema que esse arquivo
exclusivo do BDP e a tcnica no poderia ser utilizada para outros providers.
O .NET Framework oferece um mecanismo bastante interessante para permite a configurao dinmica de propriedades de componentes em tempo de
execuo, recurso conhecido como Dynamic Proprierties.
Vejamos na prtica um exemplo de utilizao do recurso. Selecione o
BdpConnection
e
abra
o
editor
da
propriedade
DynamicProprierties.ConnectionString, e marque a opo mostrada a seguir:
.10
.11
3. BdpCommand e BdpDataReader
Nesta terceira parte do curso conheceremos o componente BdpCommand
e a classe BdpDataReader do BDP.
O BdpCommand permite a execuo de comandos SQL ou
StoredProcedures no servidor. Este componente no possui um equivalente
direto nas tecnologias de acesso da VCL (dbExpress, BDE etc.).
No dbExpress, quando voc usa o componente SQLQuery e acionada seu
mtodo Open, chamado internamente um mtodo da interface ISQLCommand
e ISQLCursor para tratar a abertura da consulta. Quando voc precisa executar um comando de atualizao (Insert, Update ou Delete) diretamente, pode
usar um SQLQuery e chamar seu mtodo ExecSQL. No BDP temos um componente especializado para a execuo de comandos, o BdpCommand.
Clique em File|New|Windows Forms Application e arraste at o formulrio
um BdpConnection e um BdpCommand. Configure a propriedade
ConnectionString do BdpConnection para apontar para Employee. Aponte a
propriedade Connection do BdpCommand1 para BdpConnection1.
Vamos analisa o componente BdpCommand. Sua propriedade
CommandType especifica o tipo de comando, que pode ser Text,
StoredProcedure ou TableDirect. Essa ltima opo permite que voc acessar
uma tabela apenas pelo Nome (ex. EMPLOYEE), o que internamente transformando em um Select * from Tabela.
CommandText a instruo a ser executada, ou o nome da tabela ou Stored
Procedure. O mtodo ExecuteNonQuery executa o comando, quando no
retornar um resultset (ex. UPDATE,DELETE ou INSERT). Chame
ExecuteReader quando o comando retornar um cursor (ex. SELECT), o retorno da funo um DataReader que pode ser utilizado para varrer o resultset.
ExecuteScalar pode ser usado para retornar apenas o primeiro campo do primeiro registro (ideal para consultas do tipo SELECT MAX, COUNT ...). Continuando o exemplo, vamos ver como utilizar na prtica essas propriedades e
mtodos.
Coloque no formulrio dois ComboBoxes, trs Buttons, um ListView, dois
Labels e uma StatusBar. Seu formulrio deve estar semelhante ao mostrado a
seguir:
Nota: o uso de
CommandText
no
BdpCommand algo semelhante ao que j existia para o
ClientDataSet
ou
SQLDataSet do dbExpress.
.12
O cdigo anterior usa reflexo para preencher o ComboBox2 com os possveis valores para a propriedade CommandType do BdpCommand, que pode
ser Text, StoredProcedure ou TableDirect:
ListView1.Visible := False;
BdpCommand1.CommandText := ComboBox1.Text;
r := BdpCommand1.ExecuteNonQuery();
StatusBar1.Text := r.ToString + registros afetados;
end;
Aqui chamamos o mtodo ExecuteNonQuery do BdpCommand, que retorno o nmero de registros afetados por um Update, Delete ou Insert (exibimos esse valor na StatusBar).
Se o comando SQL retornar um conjunto de dados (um cursor), como em
uma instruo Select, precisamos chamar o mtodo ExecuteReader, que retorna
um BdpDataReader. Utilizamos ento esse objeto para varrer os registros
retornados. A leitura com um BdpDataReader forward-only e read-only, o
que pode aumentar a velocidade e escalabilidade das aplicaes. No entanto,
no feita a cache de dados (veremos mais sobre isso ao estudarmos o
BdpDataAdapter e DataSet). O BdpDataReader nesse caso semelhante a
um DataSet unidirecional do dbExpress, como o SQLDataSet.
A seguir, varremos o BdpDataReader e para cada registro lido informamos
os valores dos campos em um ListView. Isso feito no evento Click do boto
ExecuteReader:
procedure WinForm.Button2_Click(sender: System.Object; e: System.EventArgs);
var
rd: BdpDataReader;
i: integer;
LvItem: ListViewItem;
r: integer;
begin
ListView1.Clear;
ListView1.Visible := True;
BdpCommand1.CommandText := ComboBox1.Text;
rd := BdpCommand1.ExecuteReader();
{ adiciona colunas do ListView conforme colunas do DataReader }
for i := 0 to pred(rd.FieldCount) do
ListView1.Columns.Add(rd.GetName(i),80,HorizontalAlignment.Left);
{ Percorre o DataReader - leitura sequencial (forward - only)
e preenche os itens do ListView }
while rd.Read do
begin
lvItem := ListViewItem.Create;
ListView1.Items.add(LvItem);
for i := 0 to pred(rd.FieldCount) do
if i = 0 then
lvItem.Text := rd[rd.GetName(i)].ToString
else
LvItem.SubItems.Add(rd[rd.GetName(i)].ToString);
inc(r);
end;
StatusBar1.Text := r.ToString +
registros retornados;
rd.Close;
end;
.13
StatusBar1.Text := ;
end;
.14
4. BdpDataAdapter
Vimos na parte III do curso que um BdpCommand permite a execuo de
comandos SQL no banco de dados. Geralmente, ao manipularmos uma tabela
no BD atravs de uma aplicao, precisamos efetuar quatro operaes bsicas:
consulta (Select), atualizao (Update), excluso (Delete) e insero (Insert).
Dessa forma, o BdpDataAdapter abstrai em uma nica estrutura quatro
BdpCommands internos: SelectCommand, DeleteCommand, UpdateCommand
e InsertCommand, que permitem manipular os dados do BD. Alm disso, seu
mtodo Fill preenche um DataSet com os dados da consulta (o BDP permite
ainda o uso da propriedade Active como alternativa).
.15
Nota: conheceremos o
DataSet em detalhes em vrios exemplos nos captulos a
seguir deste curso. Por enquanto, importante saber
apenas que o DataSet permite a manipulao dos dados
em memria, desconectado
do banco de dados, semelhante ao que o ClientDataSet
para o DataSnap.
.16
.17
begin
BdpDataAdapter1.Active := False;
if tbStart.Text <> then
BdpDataAdapter1.StartRecord := Convert.ToInt32(tbStart.Text);
if tbMax.Text <> then
BdpDataAdapter1.MaxRecords := Convert.ToInt32(tbMax.Text);
BdpDataAdapter1.Active := True;
DataGrid1.DataSource := DataSet1.Tables[0];
BdpDataAdapter1.TableMappings.Clear;
BdpDataAdapter1.TableMappings.Add(Table,COUNTRY);
end;
Isso abre a consulta e configure o DataGrid para exibir os dados do primeiro DataTable do DataSet. Observe que configuramos as propriedades
StartRecord e MaxRecords do BdpDataAdapter para limitar o nmero de registros retornados pelo cursor. Voc pode, por exemplo, fazer cache apenas
dos registro 5 a 50. Esse recurso exclusivo do BDP.
No evento CheckedChange do CheckBox digite:
procedure TWinForm.cbContinue_CheckedChanged(sender: System.Object; e: System.EventArgs);
begin
BdpDataAdapter1.ContinueUpdateOnError := cbContinue.Checked;
end;
Execute a aplicao e faa alguns testes. Clique no boto Abrir para retornar
os dados da consulta e preencher o DataSet, bem como exibir os dados no
DataGrid:
.18
.19
.20
.21
No editor que abrir, clique no boto Add para criar um novo BdpParameter,
e configure suas propriedades conforme mostrado na figura a seguir:
.22
.23
Testando
Execute a aplicao e digite os comandos nos TextBoxes, como mostrado
na figura a seguir:
.24
7. MetaData
Neste artigo veremos como utilizar o BDP para recuperar informaes sobre os Metadados de um banco de dados, usando basicamente o mtodo
GetMetaData de BdpConnection. Voc pode utilizar esse recurso para obter
dados sobre os objetos de um banco, como nome de tabelas, colunas, tipos,
tamanhos, ndices, views, triggers, procedures etc.
Cada banco de dados possui um catlogo, um conjunto de tabelas que armazenam informaes sobre o prprio banco de dados. Por exemplo, o DB2
guarda informaes sobre TABELAS e COLUNAS em tabelas chamadas
SYSTABLES e SYSCOLUMNS. O SQL Server chama de sysobjetcs e
syscolumns. O Oracle armazena essas informaes em tabelas como
USER_TABLES e USER_COLUMNS. O InterBase / Firebird armazena informaes em vrias tabelas de sistema, iniciando com o prefixo RDB$. Para
se obter informaes sobre Metadados, basta que voc d um Select na respectiva tabela, de acordo com o banco usado.
O problema que a mesma instruo no se aplica a outro BD, pois conforme vimos, as tabelas de catlogo possuem nomes e estruturas completamente
diferentes.
Sabendo isso, a Borland quando criou o BDP definiu uma interface (chamada ISQLMetaData) para padronizar a obteno dessas informaes, no importa o banco de dados que esteja utilizando. Ou seja, h um padro, e voc
no precisar escrever diferentes instrues SQL para obter informaes desse
tipo quando precisar acessar mais de um tipo de BD.
Dessa forma, cada driver do BDP (para DB2, Oracle, IB) deve implementar
essa interface para indicar como os metadados de um BD podem ser obtidos,
e isso fica transparente ao programador.
ClubeDelphi Curso de acesso a dados no Delphi 2005 ADO.NET e BDP
Guinther Pauli DevMedia - guinther@clubedelphi.net www.clubedelphi.net
Todos os direitos reservados
.25
.26
.27
Nota: o componente DataSet
discutido em detalhes mais
adiante, ainda neste curso.
Por enquanto, basta saber que
ele responsvel pela cache
dados local de dados na aplicao cliente.
Utilize a opo Image para definir uma imagem para cada item.
Configurando o acesso a dados
A partir do Data Explorer da IDE arraste para o formulrio a conexo
Employee, para criar um BdpConnection. Coloque um BdpDataAdapter e aponte sua propriedade SelectCommand.Connection para BdpConnection1. Coloque um BdpCommand e aponte sua propriedade Connection para
BdpConnection1. Coloque um DataSet e aponte a propriedade DataSet do
BdpDataAdapter para esse componente. Seu formulrio deve estar semelhante
ao mostrado a seguir:
.28
end
else // views
begin
pNode := TreeView1.Nodes[0].Nodes[1];
dt1 := BdpConnection1.GetMetaData.GetTables(,TableType.View);
end;
for i := 0 to pred(dt1.Rows.Count) do
begin
row := dt1.Rows[i];
s1 := row[TableName].ToString;
n1 := TreeNode.Create(s1);
n1.ImageIndex := 4;
n1.SelectedImageIndex := 4;
pNode.Nodes.Add(n1);
{ Preenche Campos para cada Tabela }
dt2 := BdpConnection1.GetMetaData.GetColumns(s1,,ColumnType.Unknown);
for j := 0 to pred(dt2.Rows.Count) do
begin
row := dt2.Rows[j];
s2 := row[ColumnName].ToString;
n2 := TreeNode.Create(s2);
n2.ImageIndex := 5;
n2.SelectedImageIndex := 5;
n1.Nodes.Add(n2);
end;
end;
end;
{ Preenche Procedures }
pNode := TreeView1.Nodes[0].Nodes[2];
dt1 := BdpConnection1.GetMetaData.GetProcedures(,ProcedureType.Procedure);
for i := 0 to pred(dt1.Rows.Count) do
begin
row := dt1.Rows[i];
s1 := row[ProcName].ToString;
n1 := TreeNode.Create(s1);
n1.ImageIndex := 3;
n1.SelectedImageIndex := 3;
pNode.Nodes.Add(n1);
dt2 := BdpConnection1.GetMetaData.GetProcedureParams(s1,);
for j := 0 to pred(dt2.Rows.Count) do
begin
row := dt2.Rows[j];
s2 := row[ParamName].ToString;
n2 := TreeNode.Create(s2);
n2.ImageIndex := 5;
n2.SelectedImageIndex := 5;
n1.Nodes.Add(n2);
end;
end;
end;
O cdigo anterior monta a estrutura do TreeView no lado esquerdo do formulrio, inicializando os valores dos ns, para exibir os nomes das tabelas,
StoredProcedures e views disponveis no BD.
No evento Load do formulrio chamamos esse mtodo e abrimos a conexo:
procedure TWinForm.TWinForm_Load(sender: System.Object; e: System.EventArgs);
begin
BdpConnection1.Open;
ConfiguraTreeView;
TreeView1.CollapseAll;
end;
.29
.30
8. DataSets e DataTables
At agora conhecemos todos os recursos oferecidos pelos Managed
Providers, mais especificamente o provider da Borland (BDP). Esses componentes se encarregam de realizar operaes diretamente no BD, como conexo, execuo de comandos, transaes etc.
ClubeDelphi Curso de acesso a dados no Delphi 2005 ADO.NET e BDP
Guinther Pauli DevMedia - guinther@clubedelphi.net www.clubedelphi.net
Todos os direitos reservados
.31
Para quem est acostumado a usar os DataSets da VCL, bom saber desde j que a maneira como o .NET Framework gerencia o cursor local de dados
completamente diferente. Em outras palavras, voc no navegar pelos registros de um DataSet conforme est acostumado a fazer em aplicaes de
BD na VCL. No .NET, classes especializadas (estudadas mais adiante neste
curso) se encarregam desse papel. O DataTable nada mais que uma matriz de
dados, onde as colunas so os campos e as linhas os registros. No j o conceito de registro atual.
Neste primeiro exemplo veremos como realizar operaes bsicas sobre
um DataTable, como fazer uma varredura examinando seus registros, excluir,
alterar, adicionar e localizar registros etc.
Observe que no utilizaremos ainda o recurso de DataBindings, de forma
que acessaremos os dados do DataTable diretamente (no brao). DataBindings
discutido mais adiante neste curso.
Configurando o acesso a dados e controles do formulrio
Inicie uma nova aplicao do tipo Windows Forms Application. Expanda a
conexo Employee no Data Explorer e arraste a tabela Country para o designer.
Isso cria um BdpConnection e um BdpDataAdapter. Coloque um DataSet e
aponte a propriedade DataSet do BdpDataAdapter para esse componente.
Ative o BdpDataAdapter.
Coloque no formulrio um ListView, sete Buttons, dois TextBoxes, trs Labels
e trs ComboBoxes. Ajuste-os conforme mostrado na figura a seguir:
Varrendo registros
No evento Click do boto Listar digite o seguinte:
var
Table: DataTable;
Row: DataRow;
Col: DataColumn;
Column: DataColumn;
i,j: integer;
LvItem: ListViewItem;
begin
.32
ListView1.Clear;
Table := DataSet1.Tables[Country];
{ adiciona colunas do ListView conforme colunas do DataTable }
for i := 0 to pred(Table.Columns.Count) do
begin
Col := Table.Columns[i];
ListView1.Columns.Add(Col.ColumnName,100,HorizontalAlignment.Left);
end;
{ varra rows do DataTable }
for i := 0 to Table.Rows.Count - 1 do
begin
Row := Table.Rows[i];
lvItem := ListViewItem.Create;
ListView1.Items.add(LvItem);
for j := 0 to Table.Columns.Count - 1 do
begin
if j = 0 then
lvItem.Text := Row[j].ToString
else
LvItem.SubItems.Add(Row[j].ToString);
end;
end;
ComboBox1.Items.Clear;
for i := 0 to Table.Rows.Count - 1 do
ComboBox1.Items.Add(i.ToString);
end;
.33
begin
Table := DataSet1.Tables[Country];
Row := Table.NewRow;
Row[0] := TextBox1.Text;
Row[1] := TextBox2.Text;
Table.Rows.Add(Row);
{ varre novamente }
Button1_Click(nil,nil);
end;
.34
.35
Procurando e selecionando
O cdigo inserido no evento Click do boto Find se encarrega de encontrar
um DataRow no DataTable de acordo com o valor digitado pelo usurio no
ComboBox1:
procedure TWinForm.Button6_Click(sender: System.Object; e: System.EventArgs);
var
Table: DataTable;
Row: DataRow;
pk: array [0..0] of DataColumn;
begin
Table := DataSet1.Tables[0];
pk[0] := Table.Columns[0];
Table.PrimaryKey := pk;
Row := Table.Rows.Find(ComboBox2.Text);
if Row <> nil then
MessageBox.Show(Encontrou)
else
MessageBox.Show(No encontrou)
end;
.36
A figura abaixo mostra uma procura por todos os DataRows cujo campo
Country comece com A:
9. DataRelations
Neste artigo veremos como trabalhar com relacionamentos, usando a propriedade Relations do componente DataSet. Como j comentamos em artigos
anteriores, o DataSet permite que voc armazene em uma mesma estrutura
informaes retornadas de mltiplas tabelas do BD, em objetos DataTable. A
seguir, voc pode especificar como esses dados se relacionam, configurando
inclusive regras de integridade, que sero verificadas na aplicao cliente.
Configurando os BdpDataAdapters
Inicie uma nova aplicao do tipo Windows Forms Application. Expanda a
conexo Employee no Data Explorer e arraste a tabela Department para o
designer. Isso cria um BdpConnection e um BdpDataAdapter. Arraste tambm
a tabela Employee, para criar um segundo BdpDataAdapter.
Veja como ficou a instruo SQL do primeiro BdpDataAdapter, que recupera informaes da tabela DEPARMENT (para ver a instruo configurada,
clique de direita sobre o componente e selecione Configure Data Adapter, ou
abra o editor da propriedade SelectCommand.CommandText):
SELECT
DEPT_NO,
DEPARTMENT,
HEAD_DEPT,
MNGR_NO,
BUDGET,
LOCATION,
PHONE_NO
FROM
DEPARTMENT
.37
Gerando o DataSet
Clique de direita sobre o BdpDataAdapter1 e selecione a opo Configure
Data Adapter. Na aba DataSet selecione a opo New DataSet:
.38
Criando o relacionamento
Abra o editor da propriedade Relations do DataSet e no editor clique no
boto Add:
.39
Escolha DEPARTMENT e rode a aplicao. Observe que o DataGrid exibe um sinal + para que voc possa recuperar os registros do DataTable relacionado:
.40
.41
WriteXml e ReadXml
No evento Click do boto Abrir abrimos a consulta configurada no
BdpDataAdapter, e configuramos o DataGrid:
.42
.43
Testando
Execute a aplicao e clique no boto Abrir:
.44
11. DataBindings
Nesta parte do curso conheceremos o poderoso mecanismo de DataBindings
do .NET Framework, que permite exibir dados em controles de tela.
Onde esto os Data Controls no .NET?
Na VCL do Delphi, sempre que precisamos exibir dados de um BD fazemos uso dos famosos controles Data-Aware. Ou seja, se voc quer exibir dados de um DataSet em um Edit, por exemplo, deve usar sua verso DataAware, o DBEdit.
Isso exige que cada componente que precise exibir informaes de um BD
precise ter uma verso Data-Aware, o que conseguido implementando-se
DataLinks internos.
No .NET Framework, possvel vincular um controle de tela a uma fonte de
dados usando o recurso de DataBindings. Isso difere um pouco da VCL, pelo
fato que voc usar os mesmos controles no Data-Aware do Windows Forms
tambm em uma aplicao de BD. Basta configurar sua propriedade DataBingings
para que o controle passe a reconhecer dados. Uma outra vantagem que esse
comportamento definido na classe Control do Windows Forms, ou seja, todos os controles de tela (Button, TextBox, Label etc.) podem fazer Binding de
dados, no necessrio criar ou usar classes especficas.
Configurando o formulrio e acesso a dados
Inicie uma nova aplicao do tipo Windows Forms Application. Expanda a
conexo Employee no Data Explorer e arraste a tabela Employee para o designer.
Isso cria um BdpConnection e um BdpDataAdapter. Coloque um DataSet e
aponte a propriedade DataSet do BdpDataAdapter para esse componente.
ClubeDelphi Curso de acesso a dados no Delphi 2005 ADO.NET e BDP
Guinther Pauli DevMedia - guinther@clubedelphi.net www.clubedelphi.net
Todos os direitos reservados
Coloque agora no formulrio os seguintes componentes, conforme mostrado no formulrio a seguir (os componentes utilizados so: DataGrid, Buttoi,
TextBox, TabControl - com trs TabPages, ProgressBar, Trackbar, RadioButton,
Label, CheckBox, GroupBox, LixtBox e StatusBar):
DataBinding
Suponha agora que voc queira exibir no TextBox o valor para o campo
FIRST_NAME do DataTable EMPLOYEE. Para isso, basta apontar a propriedade DataBindings.Text como mostrado a seguir:
.45
RadioButton1.DataBindings.Add(
binding.Create(Text,DataSet1.Tables[0],FULL_NAME));
CheckBox1.DataBindings.Add(
binding.Create(Text,DataSet1.Tables[0],FULL_NAME));
TabPage1.DataBindings.Add(
binding.Create(Text,DataSet1.Tables[0],FULL_NAME));
GroupBox1.DataBindings.Add(
binding.Create(Text,DataSet1.Tables[0],FULL_NAME));
DataGrid1.DataBindings.Add(
binding.Create(CaptionText,DataSet1.Tables[0],FULL_NAME));
ProgressBar1.DataBindings.Add(
binding.Create(Value,DataSet1.Tables[0],EMP_NO));
TrackBar1.DataBindings.Add(
binding.Create(Value,DataSet1.Tables[0],EMP_NO));
{ data binding de um array para um ListBox }
ListBox1.DataSource := StrArray;
end;
Aqui chamamos o mtodo Add da propriedade DataBindings de cada controle, passando como parmetro o nome da propriedade onde o valor deve ser
mostrado e de qual datasource deve ser obtido.
Observe aqui uma grande vantagem dessa abordagem: voc pode fazer o
Binding de um valor para mais de uma propriedade de um mesmo componente.
Por exemplo, observe que fiz o Binding do valor do campo EMP_NO do
DataTable para a propriedade Value do TrackBar. Na VCL, geralmente o valor exibido no texto do controle. Aqui no temos essa limitao.
Os botes < e > fazem a navegao entre os registros, para que voc
possa ver os valores mudando nos controles que fizemos o DataBinding:
procedure TWinForm.Button5_Click(sender: System.Object; e: System.EventArgs);
begin
with BindingContext.Item[DataSet1.Tables[0],] do
Position := Position + 1;
end;
procedure TWinForm.Button4_Click(sender: System.Object; e: System.EventArgs);
begin
with BindingContext.Item[DataSet1.Tables[0],] do
Position := Position - 1;
end;
.46
12. CurrencyManager
O CurrencyManager usado para gerenciar uma lista de objetos que usam
DataBinding. Ele pode controlar o posicionamento de um DataView (lembrese que um DataTable no possui o conceito de registro atual), permitindo que
controles em tela podem ser sincronizados para exibirem sempre os dados de
um mesmo registro. Para obter um CurrencyManager, use o BindContext (uma
coleo de BindingManagerBase, que classe base de CurrencyManager)
passando como parmetro o nome do DataSource.
Neste artigo veremos operaes tpicas com o CurrencyManager, como
navegao e manipulao de dados.
Configurando os componentes do BDP
Inicie uma nova aplicao do tipo Windows Forms Application. Expanda a
conexo Employee no Data Explorer e arraste a tabela Department para o
designer. Isso cria um BdpConnection e um BdpDataAdapter. Coloque um
DataSet e aponte a propriedade DataSet do BdpDataAdapter para esse componente, e configure seu Active para True.
Coloque no formulrio trs Labels, trs TextBoxes, dez Buttons, um
ErrorProvider e um StatusBar. Ajuste os componentes no formulrio conforme
mostrado na figura a seguir:
.47
Veja a seguir o cdigo que deve ser colocado para cada um dos botes da
barra de navegao, na ordem. O que fazemos basicamente chamar os mtodos do CM (CurrencyManager):
procedure TWinForm.btFirst_Click(sender: System.Object; e: System.EventArgs);
begin
CM.Position := 0;
end;
procedure TWinForm.btPrior_Click(sender: System.Object; e: System.EventArgs);
begin
CM.Position := CM.Position - 1;
end;
procedure TWinForm.btNext_Click(sender: System.Object; e: System.EventArgs);
begin
CM.Position := CM.Position + 1;
end;
procedure TWinForm.btLast_Click(sender: System.Object; e: System.EventArgs);
begin
CM.Position := CM.Count - 1;
end;
procedure TWinForm.btCancel_Click(sender: System.Object; e: System.EventArgs);
begin
CM.CancelCurrentEdit;
end;
procedure TWinForm.btPost_Click(sender: System.Object; e: System.EventArgs);
begin
CM.EndCurrentEdit;
end;
procedure TWinForm.btDelete_Click(sender: System.Object; e: System.EventArgs);
begin
CM.RemoveAt(CM.Position);
end;
procedure TWinForm.AddNew(sender: System.Object; e: System.EventArgs);
begin
CM.AddNew;
end;
procedure TWinForm.btRefresh_Click(sender: System.Object; e: System.EventArgs);
begin
.48
CM.Refresh;
end;
procedure TWinForm.Update(sender: System.Object; e: System.EventArgs);
begin
BdpDataAdapter1.AutoUpdate;
end;
.49
Isso valida a entrada no campo, de forma que ele deve ser sempre preenchido (obrigatrio). Execute a aplicao e insira um registro, mantendo esse campo em branco. Veja o resultado:
Ordenando
ClubeDelphi Curso de acesso a dados no Delphi 2005 ADO.NET e BDP
Guinther Pauli DevMedia - guinther@clubedelphi.net www.clubedelphi.net
Todos os direitos reservados
.50
Caso queira, voc pode utilizar o novo comando for in do Delphi 2005
(anlogo ao foreach do C#), para iterar pelos itens da coleo, ao invs de usar
um for indexado.
Veja o resultado na figura abaixo, onde ordenamos a tabela pelo campo
Department. Observe que o DataGrid coloca uma pequena seta no cabealho
da coluna para indicar a ordenao.
Filtrando
ClubeDelphi Curso de acesso a dados no Delphi 2005 ADO.NET e BDP
Guinther Pauli DevMedia - guinther@clubedelphi.net www.clubedelphi.net
Todos os direitos reservados
.51
Para filtrar um DataTable, basta atribuir uma string de filtro (ex. DEPT_NO
> 100) para a propriedade RowFilter do seu DefaultView (semelhante a propriedade Filter dos DataSets da VCL, exceto que voc no precisa configurar
algo como o Filtered para True).
Digite o seguinte no evento Click do boto Filtrar:
procedure TWinForm1.Button1_Click(sender: System.Object; e: System.EventArgs);
begin
DataTable1.DefaultView.RowFilter := cbFilter.Text;
end;
Veja ainda mais alguns exemplos de filtragem que voc pode utilizar:
DEPARTMENT LIKE S%
Substring uma funo especial que pode ser usada em expresses de filtro.
Aqui selecionamos todos os departamentos onde o campo Department tenha a
segunda letra igual a u. Isso retorna, neste exemplo, Quality Assurance,
Customer Support, Customer Services e European Headquarters.
IIF(DEPT_NO<600,LOCATION=San
Francisco,LOCATION=Monterey)
IIF outra funo especial que pode ser usada em filtros. Passamos para ele
trs parmetros: O primeiro uma expresso booleana, se for verdadeira o
ADO.NET considera o segundo parmetro como sendo o filtro a ser usado,
caso contrrio, considera o terceiro. No exemplo anterior, seriam selecionados
todos os departamentos como localizao em San Francisco e DEPT_NO menor que 600 e todos os maiores que 600 que se localizam em Monterey. O
resultado pode ser visto na figura a seguir:
.52
.53
Sem IIF seria necessrio o uso de quatro expresses, com dois operadores
and e dois operadores or. Veja como simples fazer o mesmo com IIF no
exemplo anterior.
Count(Child(Relation1).EMP_NO)>2
begin
DataTable1.DefaultView.AllowDelete := cbAllowDelete.Checked;
end;
A figura abaixo mostra o funcionamento do RowStateFilter, exibindo somente os registros que foram excludos at o momento:
14. DataViews
ClubeDelphi Curso de acesso a dados no Delphi 2005 ADO.NET e BDP
Guinther Pauli DevMedia - guinther@clubedelphi.net www.clubedelphi.net
Todos os direitos reservados
.54
.55
Nota: A partir desta parte do
curso utilizaremos o Delphi
2005, no entanto sinta-se a
vontade para usar o Delphi 8,
caso queira.
Execute e teste a aplicao. Observe que cada DataGrid exibe seus respectivos dados e o filtro no interfere no outro DataGrid. As alteraes e demais
operaes de manipulao de dados (incluso, excluso etc.) so refletidas no
mesmo DataTable. Voc pode utilizar tambm no DataView os recurso que
mostramos no artigo anterior com o DefaultView do DataTable, como localizao (Find), restrio de acesso (AllowDelete, AllowNew e AllowEdit) etc.
.56
15. Expressions
Dando continuidade ao nosso curso sobre acesso a dados no Delphi for
.NET com ADO.NET e BDP, veremos neste artigo como utilizar o recurso de
Expressions do ADO.NET.
Um Expression permite que voc crie um campo para um DataTable que
pode exibir um resultado de operaes em outros campos do DataTable, como
somas, contagens, clculos, mdias etc. Esse recurso semelhante aos
Aggregates do ClientDataSet da VCL.
Configurando os componentes do BDP e ADO.NET
Inicie uma nova aplicao do tipo Windows Forms Application. Expanda a
conexo Employee no Data Explorer e arraste as tabelas Department e Employee
para o designer. Isso cria um BdpConnection e dois BdpDataAdapters. Coloque um DataSet e aponte a propriedade DataSet do BdpDataAdapter para
esse componente e configure seu Active para True. Faa o mesmo para o segundo BdpDataAdapter.
Use a propriedade Relations do DataSet para configurar um relao entre
os dois DataTables, conforme mostrado a seguir:
.57
dgcol.MappingName := Lookup;
dgcol.HeaderText := Lookup (Department);
dgcol.Width := 200;
DataGridTableStyle1.GridColumnStyles.Add(dgcol);
end;
.58
.59
Indique quais as tabelas devem ser usadas para criar a nova classe, nesse
caso somente uma:
.60
.61
columnHEAD_DEPT: DataColumn;
columnMNGR_NO: DataColumn;
columnBUDGET: DataColumn;
columnLOCATION: DataColumn;
columnPHONE_NO: DataColumn;
public
DEPARTMENTRowChanged: DEPARTMENTRowChangeEventHandler;
DEPARTMENTRowChanging: DEPARTMENTRowChangeEventHandler;
DEPARTMENTRowDeleted: DEPARTMENTRowChangeEventHandler;
DEPARTMENTRowDeleting: DEPARTMENTRowChangeEventHandler;
private
constructor Create; overload;
constructor Create(table: DataTable); overload;
public
function get_Count: Integer;
private
function get_DEPT_NOColumn: DataColumn;
function get_DEPARTMENTColumn: DataColumn;
function get_HEAD_DEPTColumn: DataColumn;
function get_MNGR_NOColumn: DataColumn;
function get_BUDGETColumn: DataColumn;
function get_LOCATIONColumn: DataColumn;
function get_PHONE_NOColumn: DataColumn;
public
function get_Item(index: Integer): DEPARTMENTRow;
[System.ComponentModel.Browsable(False)]
property Count: Integer read get_Count;
private
property DEPT_NOColumn: DataColumn read get_DEPT_NOColumn;
property DEPARTMENTColumn: DataColumn read get_DEPARTMENTColumn;
property HEAD_DEPTColumn: DataColumn read get_HEAD_DEPTColumn;
property MNGR_NOColumn: DataColumn read get_MNGR_NOColumn;
property BUDGETColumn: DataColumn read get_BUDGETColumn;
property LOCATIONColumn: DataColumn read get_LOCATIONColumn;
property PHONE_NOColumn: DataColumn read get_PHONE_NOColumn;
public
property Item[index: Integer]: DEPARTMENTRow read get_Item;
procedure AddDEPARTMENTRow(row: DEPARTMENTRow); overload;
function AddDEPARTMENTRow(DEPT_NO: string; DEPARTMENT: string; HEAD_DEPT: string;
MNGR_NO: SmallInt; BUDGET: System.Double; LOCATION: string; PHONE_NO: string): DEPARTMENTRow; overload;
function FindByDEPT_NODEPARTMENT(DEPT_NO: string; DEPARTMENT: string): DEPARTMENTRow;
function GetEnumerator: System.Collections.IEnumerator;
function Clone: DataTable; override;
strict protected
function CreateInstance: DataTable; override;
private
procedure InitVars;
strict private
procedure InitClass;
public
function NewDEPARTMENTRow: DEPARTMENTRow;
strict protected
function NewRowFromBuilder(builder: DataRowBuilder): DataRow; override;
function GetRowType: System.Type; override;
procedure OnRowChanged(e: DataRowChangeEventArgs); override;
procedure OnRowChanging(e: DataRowChangeEventArgs); override;
procedure OnRowDeleted(e: DataRowChangeEventArgs); override;
procedure OnRowDeleting(e: DataRowChangeEventArgs); override;
public
procedure RemoveDEPARTMENTRow(row: DEPARTMENTRow);
end;
.62
[System.Diagnostics.DebuggerStepThrough]
DEPARTMENTRow = class(DataRow)
strict private
tableDEPARTMENT: DEPARTMENTDataTable;
private
constructor Create(rb: DataRowBuilder);
public
function get_DEPT_NO: string;
function get_DEPARTMENT: string;
function get_HEAD_DEPT: string;
function get_MNGR_NO: SmallInt;
function get_BUDGET: System.Double;
function get_LOCATION: string;
function get_PHONE_NO: string;
procedure set_DEPT_NO(Value: string);
procedure set_DEPARTMENT(Value: string);
procedure set_HEAD_DEPT(Value: string);
procedure set_MNGR_NO(Value: SmallInt);
procedure set_BUDGET(Value: System.Double);
procedure set_LOCATION(Value: string);
procedure set_PHONE_NO(Value: string);
property DEPT_NO: string read get_DEPT_NO write set_DEPT_NO;
property DEPARTMENT: string read get_DEPARTMENT write set_DEPARTMENT;
property HEAD_DEPT: string read get_HEAD_DEPT write set_HEAD_DEPT;
property MNGR_NO: SmallInt read get_MNGR_NO write set_MNGR_NO;
property BUDGET: System.Double read get_BUDGET write set_BUDGET;
property LOCATION: string read get_LOCATION write set_LOCATION;
property PHONE_NO: string read get_PHONE_NO write set_PHONE_NO;
function IsHEAD_DEPTNull: Boolean;
procedure SetHEAD_DEPTNull;
function IsMNGR_NONull: Boolean;
procedure SetMNGR_NONull;
function IsBUDGETNull: Boolean;
procedure SetBUDGETNull;
function IsLOCATIONNull: Boolean;
procedure SetLOCATIONNull;
function IsPHONE_NONull: Boolean;
procedure SetPHONE_NONull;
end;
[System.Diagnostics.DebuggerStepThrough]
DEPARTMENTRowChangeEvent = class(EventArgs)
strict private
eventRow: DEPARTMENTRow;
eventAction: DataRowAction;
public
constructor Create(row: DEPARTMENTRow; action: DataRowAction);
function get_Row: DEPARTMENTRow;
function get_Action: DataRowAction;
property Row: DEPARTMENTRow read get_Row;
property Action: DataRowAction read get_Action;
end;
strict private
tableDEPARTMENT: DEPARTMENTDataTable;
public
constructor Create; overload;
strict protected
constructor Create(info: SerializationInfo; context: StreamingContext); overload;
public
function get_DEPARTMENT: DEPARTMENTDataTable;
[System.ComponentModel.Browsable(False)]
[System.ComponentModel.DesignerSerializationVisibilityAttribute(System.ComponentModel.DesignerSerializationVisibility.Content)]
property DEPARTMENT: DEPARTMENTDataTable read get_DEPARTMENT;
function Clone: DataSet; override;
strict protected
function ShouldSerializeTables: Boolean; override;
function ShouldSerializeRelations: Boolean; override;
procedure ReadXmlSerializable(reader: XmlReader); override;
.63
.64
type
TArrayOfSystem_Object = array of System.Object;
var
rowDEPARTMENTRow: DEPARTMENTRow;
begin
rowDEPARTMENTRow := (DEPARTMENTRow(Self.NewRow));
rowDEPARTMENTRow.ItemArray := TArrayOfSystem_Object.Create(DEPT_NO, DEPARTMENT,
HEAD_DEPT, MNGR_NO, BUDGET, LOCATION, PHONE_NO);
Self.Rows.Add(rowDEPARTMENTRow);
Result := rowDEPARTMENTRow;
end;
function DataSet1.DEPARTMENTDataTable.FindByDEPT_NODEPARTMENT(DEPT_NO: string;
DEPARTMENT: string): DEPARTMENTRow;
type
TArrayOfSystem_Object = array of System.Object;
begin
Result := (DEPARTMENTRow(Self.Rows.Find(TArrayOfSystem_Object.Create(DEPT_NO,
DEPARTMENT))));
end;
function DataSet1.DEPARTMENTDataTable.GetEnumerator: System.Collections.IEnumerator;
begin
Result := Self.Rows.GetEnumerator;
end;
function DataSet1.DEPARTMENTDataTable.Clone: DataTable;
var
cln: DEPARTMENTDataTable;
begin
cln := (DEPARTMENTDataTable(inherited Clone));
cln.InitVars;
Result := cln;
end;
function DataSet1.DEPARTMENTDataTable.CreateInstance: DataTable;
begin
Result := DEPARTMENTDataTable.Create;
end;
procedure DataSet1.DEPARTMENTDataTable.InitVars;
begin
Self.columnDEPT_NO := Self.Columns[DEPT_NO];
Self.columnDEPARTMENT := Self.Columns[DEPARTMENT];
Self.columnHEAD_DEPT := Self.Columns[HEAD_DEPT];
Self.columnMNGR_NO := Self.Columns[MNGR_NO];
Self.columnBUDGET := Self.Columns[BUDGET];
Self.columnLOCATION := Self.Columns[LOCATION];
Self.columnPHONE_NO := Self.Columns[PHONE_NO];
end;
procedure DataSet1.DEPARTMENTDataTable.InitClass;
type
TArrayOfDataColumn = array of DataColumn;
begin
Self.columnDEPT_NO := DataColumn.Create(DEPT_NO, TypeOf(string), nil, System.Data.MappingType.Element);
Self.Columns.Add(Self.columnDEPT_NO);
Self.columnDEPARTMENT := DataColumn.Create(DEPARTMENT, TypeOf(string), nil,
System.Data.MappingType.Element);
Self.Columns.Add(Self.columnDEPARTMENT);
Self.columnHEAD_DEPT := DataColumn.Create(HEAD_DEPT, TypeOf(string), nil,
System.Data.MappingType.Element);
Self.Columns.Add(Self.columnHEAD_DEPT);
Self.columnMNGR_NO := DataColumn.Create(MNGR_NO, TypeOf(SmallInt), nil, System.Data.MappingType.Element);
Self.Columns.Add(Self.columnMNGR_NO);
Self.columnBUDGET := DataColumn.Create(BUDGET, TypeOf(System.Double), nil,
System.Data.MappingType.Element);
Self.Columns.Add(Self.columnBUDGET);
Self.columnLOCATION := DataColumn.Create(LOCATION, TypeOf(string), nil, System.Data.MappingType.Element);
Self.Columns.Add(Self.columnLOCATION);
Self.columnPHONE_NO := DataColumn.Create(PHONE_NO, TypeOf(string), nil, System.Data.MappingType.Element);
Self.Columns.Add(Self.columnPHONE_NO);
Self.Constraints.Add(UniqueConstraint.Create(Constraint2, TArrayOfDataColumn.Create(Self.columnDEPT_NO,
.65
Self.columnDEPARTMENT), True));
Self.Constraints.Add(UniqueConstraint.Create(Constraint1, TArrayOfDataColumn.Create(Self.columnDEPARTMENT),
False));
Self.columnDEPT_NO.AllowDBNull := False;
Self.columnDEPARTMENT.AllowDBNull := False;
Self.columnDEPARTMENT.Unique := True;
end;
function DataSet1.DEPARTMENTDataTable.NewDEPARTMENTRow: DEPARTMENTRow;
begin
Result := (DEPARTMENTRow(Self.NewRow));
end;
function DataSet1.DEPARTMENTDataTable.NewRowFromBuilder(builder: DataRowBuilder): DataRow;
begin
Result := DEPARTMENTRow.Create(builder);
end;
function DataSet1.DEPARTMENTDataTable.GetRowType: System.Type;
begin
Result := TypeOf(DEPARTMENTRow);
end;
procedure DataSet1.DEPARTMENTDataTable.OnRowChanged(e: DataRowChangeEventArgs);
begin
inherited OnRowChanged(e);
if (Assigned(Self.DEPARTMENTRowChanged)) then
Self.DEPARTMENTRowChanged(Self, DEPARTMENTRowChangeEvent.Create((DEPARTMENTRow(e.Row)),
e.Action));
end;
procedure DataSet1.DEPARTMENTDataTable.OnRowChanging(e: DataRowChangeEventArgs);
begin
inherited OnRowChanging(e);
if (Assigned(Self.DEPARTMENTRowChanging)) then
Self.DEPARTMENTRowChanging(Self, DEPARTMENTRowChangeEvent.Create((DEPARTMENTRow(e.Row)),
e.Action));
end;
procedure DataSet1.DEPARTMENTDataTable.OnRowDeleted(e: DataRowChangeEventArgs);
begin
inherited OnRowDeleted(e);
if (Assigned(Self.DEPARTMENTRowDeleted)) then
Self.DEPARTMENTRowDeleted(Self, DEPARTMENTRowChangeEvent.Create((DEPARTMENTRow(e.Row)),
e.Action));
end;
procedure DataSet1.DEPARTMENTDataTable.OnRowDeleting(e: DataRowChangeEventArgs);
begin
inherited OnRowDeleting(e);
if (Assigned(Self.DEPARTMENTRowDeleting)) then
Self.DEPARTMENTRowDeleting(Self, DEPARTMENTRowChangeEvent.Create((DEPARTMENTRow(e.Row)),
e.Action));
end;
procedure DataSet1.DEPARTMENTDataTable.RemoveDEPARTMENTRow(row: DEPARTMENTRow);
begin
Self.Rows.Remove(row);
end;
constructor DataSet1.DEPARTMENTRow.Create(rb: DataRowBuilder);
begin
inherited Create(rb);
Self.tableDEPARTMENT := (DEPARTMENTDataTable(Self.Table));
end;
function DataSet1.DEPARTMENTRow.get_DEPT_NO: string;
begin
Result := (string(Self[Self.tableDEPARTMENT.DEPT_NOColumn]));
end;
function DataSet1.DEPARTMENTRow.get_DEPARTMENT: string;
begin
Result := (string(Self[Self.tableDEPARTMENT.DEPARTMENTColumn]));
end;
function DataSet1.DEPARTMENTRow.get_HEAD_DEPT: string;
begin
try
Result := (string(Self[Self.tableDEPARTMENT.HEAD_DEPTColumn]));
Exit;
except
on e: InvalidCastException do
.66
.67
.68
Include(Self.Relations.CollectionChanged, schemaChangedHandler);
end;
constructor DataSet1.Create(info: SerializationInfo; context: StreamingContext);
var
schemaChangedHandler: System.ComponentModel.CollectionChangeEventHandler;
ds: DataSet;
strSchema: string;
begin
inherited Create;
strSchema := (string(info.GetValue(XmlSchema, TypeOf(string))));
if (strSchema <> nil) then
begin
ds := DataSet.Create;
ds.ReadXmlSchema(XmlTextReader.Create(System.IO.StringReader.Create(strSchema)));
if (ds.Tables[DEPARTMENT] <> nil) then
Self.Tables.Add(DEPARTMENTDataTable.Create(ds.Tables[DEPARTMENT]));
Self.DataSetName := ds.DataSetName;
Self.Prefix := ds.Prefix;
Self.Namespace := ds.Namespace;
Self.Locale := ds.Locale;
Self.CaseSensitive := ds.CaseSensitive;
Self.EnforceConstraints := ds.EnforceConstraints;
Self.Merge(ds, False, System.Data.MissingSchemaAction.Add);
Self.InitVars;
end
else
Self.InitClass;
Self.GetSerializationData(info, context);
schemaChangedHandler := Self.SchemaChanged;
Include(Self.Tables.CollectionChanged, schemaChangedHandler);
Include(Self.Relations.CollectionChanged, schemaChangedHandler);
end;
function DataSet1.get_DEPARTMENT: DEPARTMENTDataTable;
begin
Result := Self.tableDEPARTMENT;
end;
function DataSet1.Clone: DataSet;
var
cln: DataSet1;
begin
cln := (DataSet1(inherited Clone));
cln.InitVars;
Result := cln;
end;
function DataSet1.ShouldSerializeTables: Boolean;
begin
Result := False;
end;
function DataSet1.ShouldSerializeRelations: Boolean;
begin
Result := False;
end;
procedure DataSet1.ReadXmlSerializable(reader: XmlReader);
var
ds: DataSet;
begin
Self.Reset;
ds := DataSet.Create;
ds.ReadXml(reader);
if (ds.Tables[DEPARTMENT] <> nil) then
Self.Tables.Add(DEPARTMENTDataTable.Create(ds.Tables[DEPARTMENT]));
Self.DataSetName := ds.DataSetName;
Self.Prefix := ds.Prefix;
Self.Namespace := ds.Namespace;
Self.Locale := ds.Locale;
Self.CaseSensitive := ds.CaseSensitive;
Self.EnforceConstraints := ds.EnforceConstraints;
Self.Merge(ds, False, System.Data.MissingSchemaAction.Add);
Self.InitVars;
end;
function DataSet1.GetSchemaSerializable: System.Xml.Schema.XmlSchema;
var
.69
stream: System.IO.MemoryStream;
begin
stream := System.IO.MemoryStream.Create;
Self.WriteXmlSchema(XmlTextWriter.Create(stream,
stream.Position := 0;
nil));
.70
.71
[WebMethod]
function Execute(SQL: string): DataSet;
.72
.73
.74
.75
e DataHub
.tem basicamente
.76
Criando o servidor
Primeiro preciso criar a aplicao servidora e configurar normalmente uma
conexo ao banco de dados (usando o BDP ou outro provider). Voe pode usar
para isso uma aplicao Windows Forms. Adicione alguns DataAdapters para
consultar / atualizar tabelas do BD. Colocamos um DataSync e na sua propriedade Providers referenciamos os DataAdapters.
.77
Criando o cliente
No lado cliente da aplicao, que tambm ser do tipo Windows Forms,
usamos um RemoteConnection para conectar ao servidor anterior (que deve
permanecer em execuo). Configuramos as propriedades ChannelType, Port,
ProviderType (de acordo com os valores configurados no servidor) e URI para
RemoteServer1.
19. BdpCopyTable
ClubeDelphi Curso de acesso a dados no Delphi 2005 ADO.NET e BDP
Guinther Pauli DevMedia - guinther@clubedelphi.net www.clubedelphi.net
Todos os direitos reservados
.78
Neste artigo damos continuidade ao nosso curso sobre ADO.NET e veremos como usar o novo componente BdpCopyTable do BDP do Delphi 2005,
usado para copiar dados entre banco de dados. Esse componente usado
internamente pela IDE do Delphi 2005, atravs do utilitrio de migrao disponvel no Data Explorer. simples us-lo em aplicaes .NET, como veremos
aqui.
Criando a aplicao Windows Forms
Inicie uma nova aplicao Windows Forms no Delphi 2005.
Conexes
preciso que voc tenha configurado pelo menos duas conexes no Data
Explorer para testar o componente. Em minha mquina tenho duas conexes
configuradas, uma para acesso ao banco Employee do Interbase e outra para o
Northwind do SQL Server. Em partes anteriores do curso j falamos sobre
criao de conexes BDP. Neste exemplo, faremos a migrao da tabela Country
do IB para o SQL Server.
.79
Configurando os componentes
Arraste a conexo Employee e Northwind para o formulrio, o que criar
dois BdpConnections. Coloque um BdpCommand, aponte para a conexo ao
IB e em CommandText digite a consulta a uma tabela: select * from
COUNTRY. Observe que com isso voc pode especificar condies para os
dados que sero migrados.
Coloque no formulrio o novo componente BdpCopyTable:
Migrando...
Coloque um Button no formulrio e no seu evento Click digite:
ClubeDelphi Curso de acesso a dados no Delphi 2005 ADO.NET e BDP
Guinther Pauli DevMedia - guinther@clubedelphi.net www.clubedelphi.net
Todos os direitos reservados
.80
Execute e teste a aplicao. A figura abaixo comprova que a tabela foi migrada com sucesso.
Com isso, fica muito simples migrar suas tabelas de um banco de dados para
outro. O BDP se encarrega de criar a estrutura e tambm migrar os dados,
conforme vimos.
.81
.82
BdpConnection1.Open();
try
BdpCommand1.Parameters[0].Value := TextBox1.Text;
BdpCommand1.ExecuteNonQuery();
Label1.Text := Convert.ToString(BdpCommand1.Parameters[1].Value);
finally
BdpConnection1.Close();
end;
end;
.83
Download
Voc pode fazer download de todos os exemplos deste curso a partir do endereo cc.borland.com/cc/ccweb.exe/author?authorid=222668
.84