Programowanie w języku Delphi » Artykuły

MS SQL Server 2000 i Delphi 7 - programowanie baz danych

WSTĘP

To jest drugi mój artykuł z cyklu programowanie baz danych. Poprzedni, dotyczący InterBase i technologii IBX można znaleźć pod adresem http://4programmers.net/article.php?id=587
Artykuł pomagał mi tworzyć Kamil Mościcki, któremu dziekuję za wszelkie uwagi i sugestie.
W tym artykule przedstawię sposób obsługi z poziomu Delphi 7 Enterprise systemu baz danych produkowanego przez Microsoft - MS SQL Server 2000. Z poziomu Delphi 7 możemy dostać się do bazy danych stworzonej w MS SQL Server 2000 poprzez kilka technologii:
  • dbExpress
  • ADO
  • ODBS
  • BDE

Ja omówię sposób połączenia z MS SQL Server 2000 za pomocą technologii ADO.
Czym jest ADO?

ADO to skrót od ActiveX Data Objects. ADO jest technologią zaprojektowaną dla programistów aplikacji. W ADO dostępne są wszystkie niezbędne mechanizmy bazodanowe, w tym także transakcje (o transakcjach będzie w dalszej części tego arta). Jednak ADO oprócz dostępu do systemów baz danych:
  • MS Access
  • MS SQL Server 2000
  • Oracle
  • Paradox

pozwala również na dostęp do innych struktur danych:
  • do plików Excel
  • do plików tekstowych Lotus
  • HTML
  • do plików tekstowych



MS SQL SERVER 2000 - KRÓTKI OPIS

MS SQL Server 2000 to bardzo rozbudowany system zarządzania bazami danych - dlatego w tej części przedstawię tylko informacje niezbędne do zrozumienia dalszej części artykułu. MS SQL Server 2000 podobnie jak Sybase Adaptive Server korzystają z dialektu SQL nazwanego Transact-SQL. Administrowanie oraz korzystanie z serwera MS SQL server w Winsows jest możliwe dzięki aplikacji o nazwie SQL Enterprise Manager (instaluje się razem z SQL Serverem). Zapytania SQL możemy wydawać z poziomu aplikacji Query Analyzer.

Ok, otwórzmy SQL Server Enterprise Manager'a i zobaczmy jak wygląda to narzędzie (Start->Programy->Microsoft SQL Server->Enterprise Manager).Ja podczas instalacji nie wpisywałem żadnych haseł - dlatego nie muszę się logować. Rysunek poniżej przedstawia Enterprise Managera.

<image>http://4programmers.net/bin/ado1.jpg</image>


Enterprise Manager jest narzędziem, które pozwala na administrowanie kilkoma serwerami SQL jednocześnie. Wymaga to od użytkownika jedynie zarejestrowania w programie wszystkich serwerów, którymi będzie zarządzał. Rejestracja wymaga wskazania Managerowi lokalizacji serwera baz danych, podania identyfikatora użytkownika oraz hasła. Po wykonaniu tych czynności można przeglądać i modyfikować wszystkie obiekty należące do bazy danych, pod warunkiem posiadania odpowiednich uprawnień.
Ok ,przyjrzyjmy się teraz Query Analyzer'owi (Start->Programy->Microsoft SQL Server->Query Analyzer). Ja podczas włączania zaznaczam opcję Windows autentyfication i klikam OK (zobacz rysunek poniżej)

<image>http://4programmers.net/bin/ado2.jpg</image>


Po wykonaniu tych czynności pojawi się nowe okno, w którym możemy wpisywać zapytania SQL(nie będę omawiał składni poleceń SQL - odsyłam do książek, artykułów lub pomocy on-line)
Przykładowe zapytania i wyniki można zobaczyć na rysunku poniżej

<image>http://4programmers.net/bin/ado3.jpg</image>


Ok, nadszedł czas aby stworzyć bazę danych. Stwórzmy bazę danych Osoby. w tym celu klikamy prawym klawiszem myszy w Enterprise Managerze na Databases i wybieramy New Database - tak jak to zostało przedstawione na rysunku poniżej.

<image>http://4programmers.net/bin/ado4.jpg</image>

Pojawi się nowe okno, w którym na zakładce General w polu Name wpisujemy nazwę bazy danych, czyli u nam Osoby. Na zakładce Data File ja zmieniłem lokalizację (Location) na C:\Documents and Settings\Hawk\Pulpit\Artykuł ADO\Osoby_Data.MDF i zmieniłem także lokalizację (Location) logów transakcji (zakładka Transaction Log) na C:\Documents and Settings\Hawk\Pulpit\Artykuł ADO\Osoby_Log.LDF - oczywiście Wy zróbcie to wg własnego uznania:) - możecie zostawić ścieżki domyślne. Na koniec należy kliknąć OK i już powinniśmy zobaczyć w gałęzi Databases utworzoną przez nas bazę a we wskazanej przez nas lokalizacji  (jeśli nie zmienialiśmy nazw) powinny utworzyć się pliki
  • Osoby_Data.MDF - plik bazy danych
  • Osoby_Log.LDF - plik logów przechowujący informacje o wykonywanych transakcjach

Teraz stwórzmy tabelę przechowującą dane o znajomych.
Klikamy na pole Tables w bazie Osoby prawym klawiszem myszy i wybieramy New Table. Proces ten pokazany jest na rysunku poniżej.

<image>http://4programmers.net/bin/ado5.jpg</image>


Warto zwrócić uwagę ze MS SQL Server sam utworzył kilka tabel - są to tabele systemowe, które przechowują różne informacje konieczne do prawidłowej pracy MS SQL Servera(i raczej nie należy ich zmieniać - no chyba ze jesteś zaawansowanym użytkownikiem MS SQL Servera 2000 i wiesz co robisz:) - ale wtedy pewnie nie czytałbyś tego arta:)). Dobra już koniec żartów - aby stworzyć tabelę trzeba uzupełnić kilka pól w nowootwartym oknie - tworzenie tabel w MS SQL Server 2000 odbywa się podobnie jak w MS Access - więc jeśli już masz jakieś doświadczenie w tworzeniu tabel w Access to bez trudu uda Ci się stworzyć tabelę w MS SQL Server 2000. Rysunek poniżej przedstawia sposób, w jaki ja stworzyłem tabelę.

<image>http://4programmers.net/bin/ado6.jpg</image>


Na atrybucie Id utworzyłem klucz główny klikając ikonę klucza w pasku narzędziowym (klucz główny tworzy się również tak samo jak w MS Access).
Następnie należy kliknąć na przycisk zamykający nowe okno - system zapyta się nas czy chcemy zapisać zmiany w nowej tabelce - klikamy Tak(Ok) i w nowootwartym oknie podajemy nazwę tabeli - ja nazwałem ją Znajomi. Od tej pory w bazie Osoby widać tabelę Znajomi (patrz na rysunek poniżej)

<image>http://4programmers.net/bin/ado7.jpg</image>



DELPHI 7 i MS SQL SERVER 2000

Do programowania baz danych w Delphi 7 Enterprise za pomocą technologii ADO mamy dostępnych kilka komponentów z palety ADO:
  • ADOConnection - służy do połączenia z bazą danych
  • ADOCommand - odpowiedzialny za wykonywanie instrukcji SQL
  • ADODataSet - odpowiednik DataSet - klasy, która prezentuje dane w postaci tabel
  • ADOTable - służy do wykonywania operacji związanych z tabelą
  • ADOQuery - odpowiedzialny za wykonywanie zapytań SQL
  • ADOStoredProc - służy do wykonywania procedur wbudowanych
  • RDSConnection - łączenie z usługą RDS
Potrzebne nam będą również komponenty bazodanowe z innych palet: Data Control(komponent DBGrid) i Data Access(komponent DataSource)

Ok, zróbmy w końcu aplikację pracującą na stworzonej przez nas bazie danych.
Otwieramy Delphi 7 Enterprise i na Formę dodajemy następujące komponenty:
  • ADOConnection1 - komponent odpowiedzialny za połączenie z bazą danych
  • ADOQuery1 - komponent odpowiedzialny za wykonywanie zapytań SQL
  • DataSource1
  • DBGrid1 - siatka do prezentacji wyników zapytań SQL
  • PopupMenu1 - menu podręczne
  • 4 Edity - do wprowadzania danych
  • 4 Labele - do zaetykietowania pól tekstowych
  • 3 Buttony - przyciski odpowiedzialne za operacje "Pokaż wszystkie rekordy", "Dodaj rekord", "Modyfikuj rekord"

Stworzony przeze mnie interfejs przedstawiony jest poniżej

<image>http://4programmers.net/bin/ado8.jpg</image>


Teraz trzeba poustawiać właściwości komponentów. Zaczynamy od komponentu ADOConnection1. Klikamy na niego prawym klawiszem myszy i wybieramy Edit ConnectionString. W nowootwartym oknie sprawdzamy czy zaznaczona jest opcja Use Connection String i wybieramy Build - otworzy się kolejne okno. Na pierwszej zakładce okna należy wybrać sterownik, który będzie obsługiwał bazę danych. Bazę mamy stworzoną w MS SQL Server 2000 więc wybieramy sterownik o nazwie Microsoft OLE DB Provider for SQL Server(patrz rysunek poniżej).

<image>http://4programmers.net/bin/ado9.jpg</image>

Teraz kliknij przycisk Dalej lub wybierz zakładkę Połączenie. Tu też trzeba ustawić parę rzeczy. W zależności od sposobu instalacji i konfiguracji MS SQL Servera 2000 należy wybrać lub uzupełnić parę pól:
  • Należy wybrać lub wprowadzić nazwę serwera
  • Wprowadzić informacje o logowaniu do serwera
  • Wybrać baze danych na serwerze

Ja nie wybierałem nazwy serwera, zaznaczyłem opcję Użyj wbudowanych zabezpieczeń systemu Windows NT i wybrałem bazę danych Osoby(patrz rysunek poniżej)

<image>http://4programmers.net/bin/ado10.jpg</image>


Możemy teraz przetestować połączenie z bazą danych klikając na przycisk Testuj połączenie. Jeśli otrzymamy informacje, że połączenie testowe powiodło się to na koniec musimy zatwierdzić wprowadzone zmiany klikając w dwóch oknach na przycisk OK.

Komponentu ADOConnection możemy nie umieszczać na Formie - każdy komponent oprócz RDSConnection ma właściwość ConnectionString - ale jeśli nie umieścimy tego komponentu, to będziemy musieli ustawić właściwość ConnectionString dla każdego komponentu oddzielnie i nie będziemy mogli skorzystać z mechanizmu transakcji.
Tak więc komponent ADOConnection jest centrum sterowania dla innych komponentów ADO i jest odpowiedzialny za transakcje.

Zmieniamy właściwość Connection komponentu ADOQuery1 na ADOConnection1.
Zmieniamy właściwość DataSet komponentu DataSource1 na ADOQuery1.
Zmieniamy właściwość DataSource komponentu DBGrid1 na DataSource1, i właściwość PopupMenu na PopupMenu1 żeby powiązać menu podręczne z siatką DBGrid1. Ja zmieniłem jeszcze właściwość Align na alTop, żeby siatka była na górze formy i właściwość Option->dgRowSelect na True, żeby podczas kliknięcia na siatkę zaznaczał się cały wiersz, a nie tylko jedna komórka.
W komponencie PopupMenu dodałem 2 pozycje Usuń rekord i Modyfikuj rekord - jak klikniemy najpierw lewym klawiszem myszy na DBGrid1 żeby zaznaczyć wiersz a potem prawym to będzie można wybrać te operacje.

Ok, nadszedł czas napisać trochę kodu:) Tworzymy procedury i funkcje odpowiedzialne za operacje SQL

procedure zapytanieSelect(zapytanie:string; ADOQuery:TADOQuery);
//procedura wykonuje zapytanie SELECT - wyświetla wszystkie dane w tabeli
begin
    ADOQuery.Close;                //zamykamy komponent Query - musimy to zrobić
    ADOQuery.SQL.Clear;            //czyścimy treść starego zapytania
    ADOQuery.SQL.Add(zapytanie);   //wpisujemy nowe zapytanie
    ADOQuery.Open;                 //wykonujemy zapytanie Open dla zapytania typu SELECT
end;
 
procedure zapytanieDelete(zapytanie:string; tabela:string; ADOQuery:TADOQuery; ADOConnection:TADOConnection);
//procedura usuwa jeden wpis z bazy danych
begin
    ADOQuery.Close;                //zamykamy komponent Query - musimy to zrobić
    ADOQuery.SQL.Clear;            //czyścimy treść starego zapytania
    ADOQuery.SQL.Add(zapytanie);   //wpisujemy nowe zapytanie
    ADOQuery.ExecSQL;              //wykonujemy zapytanie ExecSQL dla zapytań typu INSERT, UPDATE, DELETE
    ADOConnection.Connected:=False;  //rozłączamy się z bazą danych - bardzo ważny moment
    ADOConnection.Connected:=True;   //łączymy się ponownie z bazą danych
    zapytanieSelect('SELECT * FROM ' + tabela + ';', Form1.ADOQuery1);  //wykonujemy zapytanie SELECT w celu wyświetlenia zaktualizowanych rekordów
end;
 
procedure zapytanieInsert_Update(zapytanie:string;ADOQuery:TADOQuery);
//procedura dodaje jeden wpis lub modyfikuje dane w bazie danych
begin
    ADOQuery.Close;               //zamykamy komponent Query - musimy to zrobić
    ADOQuery.SQL.Clear;           //czyścimy treść starego zapytania
    ADOQuery.SQL.Add(zapytanie);  //wpisujemy nowe zapytanie
    ADOQuery.ExecSQL;             //wykonujemy zapytanie ExecSQL dla zapytań typu INSERT, UPDATE, DELETE
end;
 
function pzapytanieSelect(zapytanie:string;ADOQuery:TADOQuery;co:string):string;
//funkcja wykonuje zapytanie SELECT i zwraca wartość pola zadanego jako parametr "co"
begin
    ADOQuery.Close;               //zamykamy komponent Query - musimy to zrobić
    ADOQuery.SQL.Clear;           //czyścimy treść starego zapytania
    ADOQuery.SQL.Add(zapytanie);  //wpisujemy nowe zapytanie
    ADOQuery.Open;                //wykonujemy zapytanie Open dla zapytania typu SELECT
    result:=ADOQuery.FieldByName(co).AsString;  //zwracamy interesujące nas pole jako wynik funkcji
end;


Bardzo ważne linie kodu zamieszczam poniżej - odpowiedzialne są ona za rozłączenie i ponowne połączenie z bazą danych. Po co je stosuję? Otóż gdyby ich nie było to po wykonaniu zapytania INSERT nowy wpis zostałby dodany, ale nie zobaczylibyśmy tego - trzeba by było wyłączyć i włączyć program. A po rozłączeniu i ponownym połączeniu się z bazą danych i wykonaniu zapytania SELECT wszystko działa poprawnie - czyli widać nowododany wpis.

ADOConnection.Connected:=False;  //rozłączamy się z bazą danych - bardzo ważny moment
ADOConnection.Connected:=True;   //łączymy się ponownie z bazą danych


Oprogramujmy teraz zdarzenia onCreate i onDestroy Formy. W onCreate będziemy się łączyć z bazą danych, w onDestroy rozłączać.

procedure TForm1.FormCreate(Sender: TObject);
begin
     ADOConnection1.Connected:=True;
end;
 
procedure TForm1.FormDestroy(Sender: TObject);
begin
    ADOConnection1.Connected:=False;
end;


Mając już wszystkie niezbędne procedury i funkcji oprogramowujemy zdarzenie naciśnięcia przycisku - dodanie jednego wpisu do bazy danych

procedure TForm1.Button1Click(Sender: TObject);
var
    id:integer;//zmienna przechowująca wartość klucza głównego z tabeli znajomi
begin
    //zaczynamy blok try - chcemy pobrać maksymalną wartość klucza głównego, aby kolejny rekord zapisać pod numerem o 1 większym
    try
       //operacja służąca do wybierania maksymalnego numeru
       id:=StrToInt(pzapytanieSelect('Select Max(ID) AS Id FROM Znajomi;',ADOQuery1,'Id'));
    except
       //jeśli w bazie nie było żadnego wpisu to ustawiamy wartość klucza głównego na 0
       id:=0;
    end;
    id:=id+1;//zwiększamy o 1 wartość klucza głównego
    if (Edit1.Text<>'') and (Edit2.Text<>'') then //jeśli użytkownik wypełnił pola Edit, to znaczy wpisał Imię i Nazwisko(te pola są wymagane w bazie telefon i e-mail nie są wymagane)
    begin
       //wywołujemy procedurę dodającą nowe dane do bazy danych
       zapytanieInsert_Update('INSERT INTO Znajomi (Id, Imie_i_nazwisko, Telefon, E_mail) VALUES ('+IntToStr(Id)+', '''+Edit1.Text+' '+Edit2.Text+''', '''+Edit3.Text+''', '''+Edit4.Text+''');',ADOQuery1);
       ADOConnection1.Connected:=False;//rozłączamy sie z bazą...
       ADOConnection1.Connected:=True;//...i ponownie się z nią łączymy
       zapytanieSelect('SELECT * FROM Znajomi',ADOQuery1);//wykonujemy zapytanie Select aby wyświetlić wszystkie rekordy i sprawdzić ze naprawdę rekord został dodany
    end
    else//gdy użytownik nie uzpuenił pola imie lub nazwisko...
       showmessage('Uzupelnij pola imię i nazwisko');//..wyświetlamy odpowiedni komunikat
    Button3.Enabled:=False;//zabieg kosmetyczny - Button3 ma być aktywny tylko podczas operacji Modyfikuj
end;


teraz piszemy procedurę wyświetlającą wszystkie rekordy - kod powinien być zrozumiały - nie ma żadnych nowych operacji

procedure TForm1.Button2Click(Sender: TObject);
begin
    ADOConnection1.Connected:=False;
    ADOConnection1.Connected:=True;
    zapytanieSelect('SELECT * FROM Znajomi',ADOQuery1);
    Button3.Enabled:=False;
end;


Ok teraz nadeszła pora żeby zaprogramować usuwanie rekordu z bazy danych - zrobimy to w następujący sposób klikniemy na polu DBGRid1 wpis, który chcemy usunąć i prawym klawiszem myszy wybierzemy opcje Usuń rekord - wpis wtedy zostanie usunięty. Aby to zrobić potrzebny nam będzie komponent - PopupMenu1(menu rozwijane po kliknięciu prawym klawiszem myszy). Dla komponentu DBGrid1 ustawiliśmy właściwość PopupMenu na PopupMenu1.
Następnie stwórzmy zmienną globalną co:string; - będzie ona przechowywała numer osoby, który został kliknięty lewym klawiszem myszy. Oprogramujemy zdarzenie onCellClick komponentu DBGrid1

procedure TForm1.DBGrid1CellClick(Column: TColumn);
begin
    co:=DBGrid1.Fields[0].AsString;
    //jak klikniemy którekolwiek pole w DBGrid to zmienna "co" będzie miała wartość przechowywaną w kolumnie 0 czyli "ID" dla klikniętego rekordu
end;


Teraz zostaje nam już tylko oprogramowanie zdarzenia wybrania "Usuń rekord" dla menu podręcznego

procedure TForm1.Usurekord1Click(Sender: TObject);
begin
    zapytanieDelete('DELETE FROM znajomi WHERE Id =' + co + ';', 'znajomi', Form1.ADOQuery1, Form1.ADOConnection1);
end;


Zróbmy jeszcze sortowanie tabeli wg kolumny komponentu DBGrid1, która zostanie kliknięta. W tym celu oprogramowujemy zdarzenie onTitleClick dla komponentu DBGrid1.

procedure TForm1.DBGrid1TitleClick(Column: TColumn);
var
    atrybut:string;//zmienna wg któej będziemy sortować
begin
    atrybut:=Column.Title.Caption;//do zmiennej pobieramy nazwę kolumny
    zapytanieSelect('SELECT * FROM znajomi ORDER BY '+ atrybut +';',Form1.ADOQuery1);//wykonujemy zapytanie sortujące
    //przemalowywujemy i odświeżamy DBGrid1
    DBGRid1.Repaint;
    DBGrid1.Refresh;
end;


Zostało nam oprogramowanie Modyfikowania rekordu. Idea działania będzie następująca: Użytkownik kliknie lewym klawiszem myszy na rekord, który chce modyfikować a następnie prawym klawiszem myszy i wybierze operacje Modyfikuj rekord. Po wykonaniu tych czynności pola Edit powinny zostać uzupełnione danymi z rekordu, a przycisk Modyfikuj rekord powinien zostać uaktywniony(Enabled na True) i użytkownik może dokonać zmian w polach Edit - a następnie może kliknąć na przycisk Modyfikuj rekord i dane powinny zostać zmodyfikowane.
Ok wiec zabieramy się za oprogramowanie zdarzenia Modyfikuj rekord w menu podręcznym

procedure TForm1.Modyfikuj1Click(Sender: TObject);
var
    imie_i_nazwisko:string;//zmienna przechowująca imię i nazwisko
begin
    Button3.Enabled:=True;//przycisk do modyfikacji ma być aktywny
    identyfikator:=StrToInt(co);//musimy zapamiętać identyfikator rekordu - potrzebny będzie podczas wykonywania polecenia SQL - Update
    //pobieramy z bazy imie i nazwisko
    imie_i_nazwisko:=pzapytanieSelect('Select Imie_i_nazwisko FROM Znajomi WHERE id='+IntToStr(identyfikator)+';',ADOQuery1,'Imie_i_nazwisko');
    //rozdzielamy imię i nazwisko wg spacji i imię wpisujemy do Edit1 a nazwisko do Edit2
    Edit1.Text:=copy(imie_i_nazwisko,1,pos(' ',imie_i_nazwisko));
    Edit2.Text:=copy(imie_i_nazwisko,pos(' ',imie_i_nazwisko)+1,length(imie_i_nazwisko)-pos(' ',imie_i_nazwisko));
    //wybieramy z bazy nr telefonu i wpisujemy do Edit3
    Edit3.Text:=pzapytanieSelect('Select Telefon FROM Znajomi WHERE id='+IntToStr(identyfikator)+';',ADOQuery1,'Telefon');
    //wybieramy z bazy adres e-mail i wpisujemy do Edit4
    Edit4.Text:=pzapytanieSelect('Select E_mail FROM Znajomi WHERE id='+IntToStr(identyfikator)+';',ADOQuery1,'E_mail');
end;


i teraz oprogramowujemy naciśnięcie przycisku Modyfikuj rekord

procedure TForm1.Button3Click(Sender: TObject);
begin
    //wykonujemy zapytanie modyfikujące dane
    zapytanieInsert_Update('UPDATE Znajomi SET Imie_i_nazwisko='''+Edit1.Text+' '+Edit2.Text+''', Telefon='''+Edit3.Text+''', E_mail='''+Edit4.Text+''' WHERE id='+IntToStr(Identyfikator)+';',ADOQuery1);
    ADOConnection1.Connected:=False;//rozłączamy się...
    ADOConnection1.Connected:=True;//... i ponownie łączymy z bazą
    zapytanieSelect('SELECT * FROM Znajomi',ADOQuery1);//wykonujemy zapytanie Select
    Button3.Enabled:=False;//ustawiamy przycisk Modyfikuj dane na nieaktywny
end;


Poniżej zamieszczam kod całego programu

unit Unit1;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, DB, ADODB, StdCtrls, Grids, DBGrids, Menus;
 
type
  TForm1 = class(TForm)
    ADOConnection1: TADOConnection;
    ADOQuery1: TADOQuery;
    DataSource1: TDataSource;
    DBGrid1: TDBGrid;
    Button1: TButton;
    Button2: TButton;
    Edit1: TEdit;
    Edit2: TEdit;
    Edit3: TEdit;
    Edit4: TEdit;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Label4: TLabel;
    PopupMenu1: TPopupMenu;
    Usurekord1: TMenuItem;
    Modyfikuj1: TMenuItem;
    Button3: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure DBGrid1CellClick(Column: TColumn);
    procedure DBGrid1TitleClick(Column: TColumn);
    procedure Usurekord1Click(Sender: TObject);
    procedure Modyfikuj1Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form1: TForm1;
  co:string;
  identyfikator:integer;
 
implementation
 
{$R *.dfm}
 
procedure zapytanieSelect(zapytanie:string; ADOQuery:TADOQuery);
//procedura wykonuje zapytanie SELECT - wyświetla wszystkie dane w tabeli
begin
    ADOQuery.Close;                
    ADOQuery.SQL.Clear;            
    ADOQuery.SQL.Add(zapytanie);  
    ADOQuery.Open;                 
end;
 
procedure zapytanieDelete(zapytanie:string; tabela:string; ADOQuery:TADOQuery; ADOConnection:TADOConnection);
//procedura usuwa jeden wpis z bazy danych
begin
    ADOQuery.Close;                
    ADOQuery.SQL.Clear;            
    ADOQuery.SQL.Add(zapytanie);   
    ADOQuery.ExecSQL;              
    ADOConnection.Connected:=False;
    ADOConnection.Connected:=True; 
    zapytanieSelect('SELECT * FROM ' + tabela + ';', Form1.ADOQuery1); 
end;
 
procedure zapytanieInsert_Update(zapytanie:string;ADOQuery:TADOQuery);
//procedura dodaje jeden wpis lub modyfikuje dane w bazie danych
begin
    ADOQuery.Close;               
    ADOQuery.SQL.Clear;           
    ADOQuery.SQL.Add(zapytanie);  
    ADOQuery.ExecSQL;             
end;
 
function pzapytanieSelect(zapytanie:string;ADOQuery:TADOQuery;co:string):string;
//funkcja wykonuje zapytanie SELECT i zwraca wartość pola zadanego jako parametr "co"
begin
    ADOQuery.Close;               
    ADOQuery.SQL.Clear;           
    ADOQuery.SQL.Add(zapytanie);  
    ADOQuery.Open;                
    result:=ADOQuery.FieldByName(co).AsString;  
end;
 
 
procedure TForm1.FormCreate(Sender: TObject);
begin
     ADOConnection1.Connected:=True;
end;
 
procedure TForm1.FormDestroy(Sender: TObject);
begin
    ADOConnection1.Connected:=False;
end;
 
procedure TForm1.Button1Click(Sender: TObject);
var
    id:integer;
begin
    try
       id:=StrToInt(pzapytanieSelect('Select Max(ID) AS Id FROM Znajomi;',ADOQuery1,'Id'));
    except
       id:=0;
    end;
    id:=id+1;
    if (Edit1.Text<>'') and (Edit2.Text<>'') then
    begin
       zapytanieInsert_Update('INSERT INTO Znajomi (Id, Imie_i_nazwisko, Telefon, E_mail) VALUES ('+IntToStr(Id)+', '''+Edit1.Text+' '+Edit2.Text+''', '''+Edit3.Text+''', '''+Edit4.Text+''');',ADOQuery1);
       ADOConnection1.Connected:=False;
       ADOConnection1.Connected:=True;
       zapytanieSelect('SELECT * FROM Znajomi',ADOQuery1);
    end
    else
       showmessage('Uzupelnij pola imię i nazwisko');
    Button3.Enabled:=False;
end;
 
procedure TForm1.Button2Click(Sender: TObject);
begin
    ADOConnection1.Connected:=False;
    ADOConnection1.Connected:=True;
    zapytanieSelect('SELECT * FROM Znajomi',ADOQuery1);
    Button3.Enabled:=False;
end;
 
procedure TForm1.DBGrid1CellClick(Column: TColumn);
begin
    co:=DBGrid1.Fields[0].AsString;
end;
 
procedure TForm1.DBGrid1TitleClick(Column: TColumn);
var
    atrybut:string;
begin
    atrybut:=Column.Title.Caption;
    zapytanieSelect('SELECT * FROM znajomi ORDER BY '+ atrybut +';',Form1.ADOQuery1);
    DBGRid1.Repaint;
    DBGrid1.Refresh;
end;
 
procedure TForm1.Usurekord1Click(Sender: TObject);
begin
    zapytanieDelete('DELETE FROM znajomi WHERE Id =' + co + ';', 'znajomi', Form1.ADOQuery1, Form1.ADOConnection1);
end;
 
procedure TForm1.Modyfikuj1Click(Sender: TObject);
var
    imie_i_nazwisko:string;
begin
    Button3.Enabled:=True;
    identyfikator:=StrToInt(co);
    imie_i_nazwisko:=pzapytanieSelect('Select Imie_i_nazwisko FROM Znajomi WHERE id='+IntToStr(identyfikator)+';',ADOQuery1,'Imie_i_nazwisko');
    Edit1.Text:=copy(imie_i_nazwisko,1,pos(' ',imie_i_nazwisko));
    Edit2.Text:=copy(imie_i_nazwisko,pos(' ',imie_i_nazwisko)+1,length(imie_i_nazwisko)-pos(' ',imie_i_nazwisko));
    Edit3.Text:=pzapytanieSelect('Select Telefon FROM Znajomi WHERE id='+IntToStr(identyfikator)+';',ADOQuery1,'Telefon');
    Edit4.Text:=pzapytanieSelect('Select E_mail FROM Znajomi WHERE id='+IntToStr(identyfikator)+';',ADOQuery1,'E_mail');
end;
 
procedure TForm1.Button3Click(Sender: TObject);
begin
    zapytanieInsert_Update('UPDATE Znajomi SET Imie_i_nazwisko='''+Edit1.Text+' '+Edit2.Text+''', Telefon='''+Edit3.Text+''', E_mail='''+Edit4.Text+''' WHERE id='+IntToStr(Identyfikator)+';',ADOQuery1);
    ADOConnection1.Connected:=False;
    ADOConnection1.Connected:=True;
    zapytanieSelect('SELECT * FROM Znajomi',ADOQuery1);
    Button3.Enabled:=False;
end;
 
end.


POniżej prezentuję program podczas działania

<image>http://4programmers.net/bin/ado11.jpg</image>



MECHANIZM TRANSAKCJI

Za tranzakcyjność w ADO odpowiada komponent ADOConnection. Używanie mechanizmu transakcji powinno przebiegać wg następującego schematu:

ADOConnection1.BeginTrans;//uruchamianie mechanizmu transakcji
try
    ADOConnection1.CommitTrans;//utrwalamy zmiany
except
    ADOConnection1.RollbackTrans;//jeśli coś się nie udało to wycofujemy transakcję
end;


Czym jest transakcja?
Jest to czynność, która powinna być wykonana w całości, albo w całości wycofana. Transakcaja ma 4 charakterystyczne cechy oznaczane skrótem ACID:
  • Atomicity - niepodzielność, transakcja jest wykonywana w całości lub wcale;
  • Consistency - spójność, transakcja doprowadza do spójnego stanu bazy danych;
  • Isolation - izolacja, transakcje nie widzą się nawzajem;
  • Durability - trwałość, wykonanie transakcji może być przerwane na pewien moment, a następnie wznowione zachowując trwałość całej operacji.

Niektórzy jeszcze wyodrębniaja5 cechę:
  • Serializability - szeregowalność, wynik transakcji współbieżnych jest taki, jak gdyby transakcje zostały wykonane sekwencyjnie jedna po drugiej.

Dlaczego tak ważne są transakcje w systemach baz danych? Po prostu dlatego, że dane muszą być zapisane lub zmodyfikowane w całości, bo co nam z niepełnych danych.

Ok, zróbmy mechanizm tranzakcyjności w naszym programie.

Dla przycisku Dodaj rekord zmieniamy kod obsługi zdarzenia onClick na następujący

procedure TForm1.Button1Click(Sender: TObject);
var
    id:integer;
begin
    try
       id:=StrToInt(pzapytanieSelect('Select Max(ID) AS Id FROM Znajomi;',ADOQuery1,'Id'));
    except
       id:=0;
    end;
    id:=id+1;
    if (Edit1.Text<>'') and (Edit2.Text<>'') then
    begin
       ADOConnection1.BeginTrans;
       try
          zapytanieInsert_Update('INSERT INTO Znajomi (Id, Imie_i_nazwisko, Telefon, E_mail) VALUES ('+IntToStr(Id)+', '''+Edit1.Text+' '+Edit2.Text+''', '''+Edit3.Text+''', '''+Edit4.Text+''');',ADOQuery1);
          ADOConnection1.CommitTrans;
       except
          ADOConnection1.RollbackTrans;
       end;
       ADOConnection1.Connected:=False;
       ADOConnection1.Connected:=True;
       zapytanieSelect('SELECT * FROM Znajomi',ADOQuery1);
    end
    else
       showmessage('Uzupelnij pola imię i nazwisko');
    Button3.Enabled:=False;
end;


Jedyną operacją w tej procedurze, która może zmienić bazę danych jest zapytanie Insert i właśnie transakcja będzie dotyczyła tylko tego zapytania. Oczywiście w mechanizmie obsługi transakcji nie możemy rozłączać się i ponownie łączyć z bazą, więc instrukcje
ADOConnection1.Connected:=False;
ADOConnection1.Connected:=True;

nie mogą być zawarte w bloku try...except.

Podobnie zmieniamy kod procedury onClick przycisku Modyfikuj rekord na następujący

procedure TForm1.Button3Click(Sender: TObject);
begin
    ADOConnection1.BeginTrans;
    try
       zapytanieInsert_Update('UPDATE Znajomi SET Imie_i_nazwisko='''+Edit1.Text+' '+Edit2.Text+''', Telefon='''+Edit3.Text+''', E_mail='''+Edit4.Text+''' WHERE id='+IntToStr(Identyfikator)+';',ADOQuery1);
       ADOConnection1.CommitTrans;
    except
       ADOConnection1.RollbackTrans;
    end;
    ADOConnection1.Connected:=False;
    ADOConnection1.Connected:=True;
    zapytanieSelect('SELECT * FROM Znajomi',ADOQuery1);
    Button3.Enabled:=False;
end;


Została nam jeszcze do zmiany procedura usuwająca rekord

procedure TForm1.Usurekord1Click(Sender: TObject);
begin
    ADOConnection1.BeginTrans;
    try
       zapytanieDelete('DELETE FROM znajomi WHERE Id =' + co + ';', Form1.ADOQuery1, Form1.ADOConnection1);
       ADOConnection1.CommitTrans;
    except
       ADOConnection1.RollbackTrans;
    end;
    ADOConnection1.Connected:=False;
    ADOConnection1.Connected:=True;
    zapytanieSelect('SELECT * FROM znajomi;', Form1.ADOQuery1);  
end;


Musiałem dodatkowo nieco zmienić procedurę zapytanieDelete żeby wewnątrz tej procedury nie wykonywać instrukcji rozłączania i łączenia się z bazą danych
procedure zapytanieDelete(zapytanie:string; ADOQuery:TADOQuery; ADOConnection:TADOConnection);
//procedura usuwa jeden wpis z bazy danych
begin
    ADOQuery.Close;                //zamykamy komponent Query - musimy to zrobić
    ADOQuery.SQL.Clear;            //czyścimy treść starego zapytania
    ADOQuery.SQL.Add(zapytanie);   //wpisujemy nowe zapytanie
    ADOQuery.ExecSQL;              //wykonujemy zapytanie ExecSQL dla zapytań typu INSERT, UPDATE, DELETE
end;


Cały kod programu wygląda teraz następująco

unit Unit1;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, DB, ADODB, StdCtrls, Grids, DBGrids, Menus;
 
type
  TForm1 = class(TForm)
    ADOConnection1: TADOConnection;
    ADOQuery1: TADOQuery;
    DataSource1: TDataSource;
    DBGrid1: TDBGrid;
    Button1: TButton;
    Button2: TButton;
    Edit1: TEdit;
    Edit2: TEdit;
    Edit3: TEdit;
    Edit4: TEdit;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Label4: TLabel;
    PopupMenu1: TPopupMenu;
    Usurekord1: TMenuItem;
    Modyfikuj1: TMenuItem;
    Button3: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure DBGrid1CellClick(Column: TColumn);
    procedure DBGrid1TitleClick(Column: TColumn);
    procedure Usurekord1Click(Sender: TObject);
    procedure Modyfikuj1Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form1: TForm1;
  co:string;
  identyfikator:integer;
 
implementation
 
{$R *.dfm}
 
procedure zapytanieSelect(zapytanie:string; ADOQuery:TADOQuery);
//procedura wykonuje zapytanie SELECT - wyświetla wszystkie dane w tabeli
begin
    ADOQuery.Close;
    ADOQuery.SQL.Clear;
    ADOQuery.SQL.Add(zapytanie);
    ADOQuery.Open;
end;
 
procedure zapytanieDelete(zapytanie:string; ADOQuery:TADOQuery; ADOConnection:TADOConnection);
//procedura usuwa jeden wpis z bazy danych
begin
    ADOQuery.Close;
    ADOQuery.SQL.Clear;
    ADOQuery.SQL.Add(zapytanie);
    ADOQuery.ExecSQL;
end;
 
procedure zapytanieInsert_Update(zapytanie:string;ADOQuery:TADOQuery);
//procedura dodaje jeden wpis lub modyfikuje dane w bazie danych
begin
    ADOQuery.Close;
    ADOQuery.SQL.Clear;
    ADOQuery.SQL.Add(zapytanie);
    ADOQuery.ExecSQL;
end;
 
function pzapytanieSelect(zapytanie:string;ADOQuery:TADOQuery;co:string):string;
//funkcja wykonuje zapytanie SELECT i zwraca wartość pola zadanego jako parametr "co"
begin
    ADOQuery.Close;
    ADOQuery.SQL.Clear;
    ADOQuery.SQL.Add(zapytanie);
    ADOQuery.Open;
    result:=ADOQuery.FieldByName(co).AsString;
end;
 
 
procedure TForm1.FormCreate(Sender: TObject);
begin
     ADOConnection1.Connected:=True;
end;
 
procedure TForm1.FormDestroy(Sender: TObject);
begin
    ADOConnection1.Connected:=False;
end;
 
procedure TForm1.Button1Click(Sender: TObject);
var
    id:integer;
begin
    try
       id:=StrToInt(pzapytanieSelect('Select Max(ID) AS Id FROM Znajomi;',ADOQuery1,'Id'));
    except
       id:=0;
    end;
    id:=id+1;
    if (Edit1.Text<>'') and (Edit2.Text<>'') then
    begin
       ADOConnection1.BeginTrans;
       try
          zapytanieInsert_Update('INSERT INTO Znajomi (Id, Imie_i_nazwisko, Telefon, E_mail) VALUES ('+IntToStr(Id)+', '''+Edit1.Text+' '+Edit2.Text+''', '''+Edit3.Text+''', '''+Edit4.Text+''');',ADOQuery1);
          ADOConnection1.CommitTrans;
       except
          ADOConnection1.RollbackTrans;
       end;
       ADOConnection1.Connected:=False;
       ADOConnection1.Connected:=True;
       zapytanieSelect('SELECT * FROM Znajomi',ADOQuery1);
    end
    else
       showmessage('Uzupelnij pola imię i nazwisko');
    Button3.Enabled:=False;
end;
 
procedure TForm1.Button2Click(Sender: TObject);
begin
    ADOConnection1.Connected:=False;
    ADOConnection1.Connected:=True;
    zapytanieSelect('SELECT * FROM Znajomi',ADOQuery1);
    Button3.Enabled:=False;
end;
 
procedure TForm1.DBGrid1CellClick(Column: TColumn);
begin
    co:=DBGrid1.Fields[0].AsString;
end;
 
procedure TForm1.DBGrid1TitleClick(Column: TColumn);
var
    atrybut:string;
begin
    atrybut:=Column.Title.Caption;
    zapytanieSelect('SELECT * FROM znajomi ORDER BY '+ atrybut +';',Form1.ADOQuery1);
    DBGRid1.Repaint;
    DBGrid1.Refresh;
end;
 
procedure TForm1.Usurekord1Click(Sender: TObject);
begin
    ADOConnection1.BeginTrans;
    try
       zapytanieDelete('DELETE FROM znajomi WHERE Id =' + co + ';', Form1.ADOQuery1, Form1.ADOConnection1);
       ADOConnection1.CommitTrans;
    except
       ADOConnection1.RollbackTrans;
    end;
    ADOConnection1.Connected:=False;
    ADOConnection1.Connected:=True;
    zapytanieSelect('SELECT * FROM znajomi;', Form1.ADOQuery1);  
end;
 
procedure TForm1.Modyfikuj1Click(Sender: TObject);
var
    imie_i_nazwisko:string;
begin
    Button3.Enabled:=True;
    identyfikator:=StrToInt(co);
    imie_i_nazwisko:=pzapytanieSelect('Select Imie_i_nazwisko FROM Znajomi WHERE id='+IntToStr(identyfikator)+';',ADOQuery1,'Imie_i_nazwisko');
    Edit1.Text:=copy(imie_i_nazwisko,1,pos(' ',imie_i_nazwisko));
    Edit2.Text:=copy(imie_i_nazwisko,pos(' ',imie_i_nazwisko)+1,length(imie_i_nazwisko)-pos(' ',imie_i_nazwisko));
    Edit3.Text:=pzapytanieSelect('Select Telefon FROM Znajomi WHERE id='+IntToStr(identyfikator)+';',ADOQuery1,'Telefon');
    Edit4.Text:=pzapytanieSelect('Select E_mail FROM Znajomi WHERE id='+IntToStr(identyfikator)+';',ADOQuery1,'E_mail');
end;
 
procedure TForm1.Button3Click(Sender: TObject);
begin
    ADOConnection1.BeginTrans;
    try
       zapytanieInsert_Update('UPDATE Znajomi SET Imie_i_nazwisko='''+Edit1.Text+' '+Edit2.Text+''', Telefon='''+Edit3.Text+''', E_mail='''+Edit4.Text+''' WHERE id='+IntToStr(Identyfikator)+';',ADOQuery1);
       ADOConnection1.CommitTrans;
    except
       ADOConnection1.RollbackTrans;
    end;
    ADOConnection1.Connected:=False;
    ADOConnection1.Connected:=True;
    zapytanieSelect('SELECT * FROM Znajomi',ADOQuery1);
    Button3.Enabled:=False;
end;
 
end.




KOMPONENT ADOCOMMAND

ADOCommand to nowy komponent(nie ma odpowiedników w innych technologiach) służący do wykonywania zapytań SQL. Prześledźmy jego działanie na przykładzie.
Stwórzmy nowy projekt i na formie umieśćmy następujące komponenty:
  • DBGrid1
  • ADOConnection1
  • ADOQuery1
  • ADOCommand
  • ADODataSet1
  • DataSource1
  • 4 Edity
  • 4 Labele
  • Button

Interfejs programu przedstawiony jest na rysunku poniżej.

<image>http://4programmers.net/bin/ado18.jpg</image>


Ustawiamy ADOConnection1 tak żeby współpracował z bazą danych Osoby (proces opisałem wyżej).
Własciwość Connection komponentu ADOCommand1 ustawiamy na ADOConection1.
Własciwość Connection komponentu ADODataSet11 ustawiamy na ADOConection1.
Własciwość CommandText komponentu ADOdataSet1 ustawiamy na Select * From Znajomi - zapytanie to będzie pokazywało nam wszystkie rekordy, jakie znajdują się w bazie danych.
Właściwość DataSet komponentu DataSource1 ustawiamy na ADODataSet1.
Właściwość Connection komponentu ADOQuery1 ustawiamy na ADOConection1.
Właściwość DataSource komponentu DBGrid1 ustawiamy na DataSource1.
Właściwość LoginPrompt komponentu ADOConnection1 zmieniamy na False - żeby nie pokazywało sie okno logowania.
Właściwość Active komponentuADODataSet1 ustawiamy na True.

I teraz musimy już tylko oprogramować zdarzenie onClick dla przycisku - będzie on dodawał nowy rekord do bazy danych za pomocą komponentu ADOCommand1.

procedure TForm1.Button1Click(Sender: TObject);
var
    id:integer;//zmienna przechowująca wartość klucza głównego
begin
    try
       //przypisanie wartości klucza głównego
       id:=StrToInt(pzapytanieSelect('SELECT MAX(Id) AS Id FROM Znajomi;',ADOQuery1,'Id'));
       id:=id+1;//zwiększenie wartości o 1
    except
       id:=1;//jeśli nic nie było w bazie ustawiamy wartość klucza na 1
    end;
    //przypisujemy treść zapytania INSERT do komponentu ADOCommand
    ADOCommand1.CommandText:='INSERT INTO Znajomi VALUES ('+IntToStr(id)+', '''+Edit1.Text+' '+Edit2.Text+''', '''+Edit3.Text+''', '''+Edit4.Text+''');';
    ADOCommand1.Execute;//wykonujemy zapytanie
    //poniższy zabieg robimy po to, żeby uaktualnić wygląd DBGrid1 ? każdorazowo, gdy właściwość active ustawiana jest na True to wykonywane jest zapytanie zapisane we właściwości CommandText, czyli SELECT * FROM Znajomi;
    ADODataSet1.Active:=False;
    ADODataset1.Active:=True;
end;


Oczywiście powyżej użyłem dobrze znanej już funkcji pzapytanieSelect. Oto jest treść.

function pzapytanieSelect(zapytanie:string;ADOQuery:TADOQuery;co:string):string;
//funkcja wykonuje zapytanie SELECT i zwraca wartość pola zadanego jako parametr "co"
begin
    ADOQuery.Close;
    ADOQuery.SQL.Clear;
    ADOQuery.SQL.Add(zapytanie);
    ADOQuery.Open;
    result:=ADOQuery.FieldByName(co).AsString;
end;


...i kod całego programu

unit Unit1;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, DB, ADODB, Grids, DBGrids;
 
type
  TForm1 = class(TForm)
    DBGrid1: TDBGrid;
    DataSource1: TDataSource;
    ADOConnection1: TADOConnection;
    ADOCommand1: TADOCommand;
    ADODataSet1: TADODataSet;
    Button1: TButton;
    Edit1: TEdit;
    Edit2: TEdit;
    Edit3: TEdit;
    Edit4: TEdit;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Label4: TLabel;
    ADOQuery1: TADOQuery;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.dfm}
 
function pzapytanieSelect(zapytanie:string;ADOQuery:TADOQuery;co:string):string;
//funkcja wykonuje zapytanie SELECT i zwraca wartość pola zadanego jako parametr "co"
begin
    ADOQuery.Close;
    ADOQuery.SQL.Clear;
    ADOQuery.SQL.Add(zapytanie);
    ADOQuery.Open;
    result:=ADOQuery.FieldByName(co).AsString;
end;
 
procedure TForm1.Button1Click(Sender: TObject);
var
    id:integer;
begin
    try
       id:=StrToInt(pzapytanieSelect('SELECT MAX(Id) AS Id FROM Znajomi;',ADOQuery1,'Id'));
       id:=id+1;
    except
       id:=1;
    end;
    ADOCommand1.CommandText:='INSERT INTO Znajomi VALUES ('+IntToStr(id)+', '''+Edit1.Text+' '+Edit2.Text+''', '''+Edit3.Text+''', '''+Edit4.Text+''');';
    ADOCommand1.Execute;
    ADODataSet1.Active:=False;
    ADODataset1.Active:=True;
end;
 
end.


i screen prezentujący działanie programu

<image>http://4programmers.net/bin/ado19.jpg</image>



MOTOR JET

Technologia ADO pozwala na dostęp nie tylko do baz danych ale także do innych struktur danych. Zobaczmy jak to działa na przykładzie. Połączymy się z plikiem Excela. Ja stworzyłem sobie plik Zeszyt1 w MS Excel Xp i w arkuszu 1 wpisałem przykładowe dane(patrz rysunek poniżej)

<image>http://4programmers.net/bin/ado12.jpg</image>


Teraz nadeszła pora otworzyć Delphi i stworzyć interfejs. Ja umieściłem na Formie następuące komponenty:
  • DNGrid1 - do wizualizacji danych
  • ADOConnection1 - do połączenia sie z Excelem
  • ADODataset
  • DataSource

Teraz należy kliknąć prawym klawiszem myszy na komponent ADOConnection1 i wybrać Edit ConnectionString a następnie nacisnąć przycisk Build. Kolejnym krokiem jest wybranie sterownika Microsoft JET 4.0 OLE DB Providerna zakładce dostawca(patrz rysunek niżej)

<image>http://4programmers.net/bin/ado13.jpg</image>


Klikamy na Dalej lub przechodzimy na zakładkę Połączenia i w polu wybierz lub wprowadź nazwę bazy danych wpisujemy lub wskazujemy ścieżkę do pliku Zeszyt1.xls(patrz rysunek niżej)

<image>http://4programmers.net/bin/ado14.jpg</image>


Następnie przechodzimy na zakładkę Wszystkie i klikamy dwukrotnie na pozycję Extended Properties i w pole wartość wpisujemy Excel 8.0 (dla Excela 2000 i Xp taka wartość działa)

<image>http://4programmers.net/bin/ado15.jpg</image>


klikamy na Ok i możemy przejść na zakładkę Połączenie i przetestować połączenie z plikiem klikając na przycisk Testuj połączenie. Wszystko powinno być OK.
Tak wiec klikamy dwukrotnie na kolejnych oknach Ok i przystępujemy do dalszej pracy.

Ustawiamy właściwość DataSet komponentu na ADODataSet1.
Ustawiamy właściwość DataSource komponentu DBGrid1 na Datasource1.
Ustawiamy właściwość Connection komponentu ADODataSet1 na ADOconnection1.
Ustawiamy właściwość CommandType komponentu ADODataSet1 na cmdTableDirect.
Ustawiamy właściwość CommandText komponentu ADODataSet1 na Arkusz1.
Ustawiamy właściwość LoginPrompt komponentu ADOConnection1 na False - żeby nie pojawiało się okno z logowaniem
Ustawiamy właściwość Active komponentu ADODataSet1 na True - w DBGrid powinny pojawić sie dane z excela

Teraz możemy już uruchomić program i dokonywać zmian na danych z pliku Excela. Poniżej przedstawiam screena z działającego programu.

<image>http://4programmers.net/bin/ado16.jpg</image>


i screena, który pokazuje, że dane w pliku Excela faktycznie zostały zmienione(w polu B3 jest teraz 1 a była liczba 432)

<image>http://4programmers.net/bin/ado17.jpg</image>


Ufff, to by było na tyle - mam nadzieję, że artykuł się przyda:) - Pozdrawiam

16 komentarzy

B-A-D 2006-04-16 12:23

Rok później...
Ludomir tobie też smacznego jajka i szczęśliwego buggs'a! :)
Świetny artykuł!!

Artur 2005-06-23 10:42

Broniu - jeśli chodzi o łączenie i rozłączanie - to masz rację - znam już lepsze metody odświeżania danych(muszę tylko przetestować) - zresztą bez rozłączania i łaczenia też dane się odświeżają - sprawdziłem. Natomiast jeśli chodzi o drugą cześć twojego komentarza -"Warto tez wspomniec o darmowych komponentach do obsługi baz danych jakimi są ZEOS-y. Które mogą wspólpracować z wieloma bazami danych w tym z mssql" - nie mam doświadczenia w pisaniu programów w Zoes - dlatego o tym nie wspomniałem

broniu 2005-06-23 08:33

Zaskoczylo mnie to rozłaczanie i łaczenie z baza po wykonaniu każdej aktualizacji, kompletnie bez sensu :]. Gdyby faktycznie tak trzeba bylo robic to wydajnosć aplikacji byłaby mizerna. Jedyny przypadek w którym nie widać wprowadzonych danych jest przy stosowaniu transakcji.Wtedy zmian nie widzą inne połaczenia i zanim transakcja nie zostanie zatwierdzona to nawet restart tych aplikacji nie pomoze. Warto tez wspomniec o darmowych komponentach do obsługi baz danych jakimi są ZEOS-y. Które mogą wspólpracować z wieloma bazami danych w tym z mssql. :D
Pozdrawiam.

tomi__m 2005-05-04 16:13

Bardzo dobry artykuł.

Marooned 2005-04-20 23:31

Artur - racja :)
Warto tylko można było wspomnieć, że nie zastosowano zabezpieczeń etc. właśnie w celu nie zaciemnienia kodu :)

Ale gratuluję chęci do pisania.

bedek 2005-03-31 13:27

Artykuł dobrze przygotowany, o wiele lepszy niż poprzedni, skoro ma być zachętą dobrze byłoby przedstawić w ramach wstępu zalety z korzystania baz typu SQL (wspomnieć o bardziej zaawansowanych funkcjach serwerów SQL)

Artur 2005-03-29 18:40

Marooned  - oczywiście, że korzystanie z parametrów w zapytaniu to lepsza a przynajmniej bardziej elegancka forma programowania - ale to jest tylko artykuł, który ma zachęcić użytkowników do dalszego poznawania tej technologii - oczywiście w tym zapytaniu \'DELETE FROM znajomi WHERE Id =\' + co +.... - nie ma możliwości wpisania apostrofu - bo \"co\" - to jest zmienna którą pobiera aplikacja podczas klikania na odpowiednią komórkę DBGrid. Poza tym faktycznie nie zabezpieczałem programu przed tego typu błędami - chodziło mi o pokazanie sedna jeśli chodzi o ADO - a zabezpieczanie programu tylko zaciemnia kod

Marooned 2005-03-29 17:15

Sugeruję używać parametrów do budowy zapytania gdyż to, co robisz:
zapytanieDelete(\'DELETE FROM znajomi WHERE Id =\' + co +....
stwarza okazję do (nawet przypadkowych) ataków typu SQL Injection.
Nie odpalałem tego programu, ale testowałem inny, który rozłożyłem na łopatki wpisując w jakiegoś edita apostrof (\') - zakończył on zapytanie SQL i wykrzaczył cały program.

abc 2005-03-29 15:39

Tu Marooned
Przez błąd systemu Coyote Twój komentarz został niechcąco usunięty. We are really sorry.
Ale pytania zadawaj raczej na forum niż tu.

Artur 2005-03-28 17:26

abc - zanim zmienisz właściwość Active komponentu ADOQuery na True musisz wpisać jakieś zapytanie we właściwość SQL tego komponentu - kliknij dwa razy na tę właściwość  i w nowootwartym oknie wpisz zapytanie typu Select - jeśli ćwiczysz na bazie stworzonej w arcie to wpisz select * From znajomi; - i dopiero zmień właściwość Active na True

fatalerror 2005-03-28 18:27

super arcik :)

prośba do autora o odpowiedż na:
http://forum.4programmers.net/viewtopic.php?id=68936

Ludomir 2005-03-27 17:07

gratuluję artykułu :) to jest prawdziwa porzadna publikacja jak przystało na 4programmers.net.

jestes moim idolem :)

Smacznego jajka i szczęśliwego królika!

Młody 2005-03-27 14:32

Cool :) Takich więcej :)

abc 2005-03-27 14:07

tego właśnie szukałem od X czasu - spox artykul oby takich wiecej na 4programmers :D
P.S. Z tym sobie nie poradzę :/
adoq.Active:=true; I wyskakuje błąd:
"MSSQL MISSING PROPERTY"
POmożecie ?

brodny 2005-03-27 13:39

To się robi nudne, że cały czas muszę takie wysokie oceny wystawiać :P Gratuluję kolejnego dobrego tekstu. Jakbyś mógł tylko screeny trochę zmniejszyć, bo rozrzucają one bardzo stronę (albo po prostu przeskalować w treści, po kliknięciu powiększenie).