Lanet olsun sana ey zalim nesne,
Beni değirmende taşa döndürdün
Kendi kendine ne mırıldanıp duruyon Asım ? Gel yanıma sana bişeler gösterecem.
Geliyom abi...
.....
.....
Şimdi yapacağım şey bazı veritabanı işlemleri için kendi nesnemi oluşturup işlemleri bu nesneye yıkmak, Asım. Ben nesneye sadece "şu hesaptan şu hesaba şu miktarı havale yap" diye emir verip işlemin nesne tarafından yapılmasını sağlayacam.
Abi "Zengin yedek kulubesi" ne ne oldu ?
Ona biraz ara verdik ilerde tekrar dönecez Asım. Sen şimdi buraya konserve ol bakim.
İlk önce her hangi bir veritabanında CARI adında bir tablo oluşturalım ve bu tabloya aşağıdakilere uygun bir şekilde alanları ekleyelim. Ben firebird kullandım, tablonun ddl ise aşağıda gözüken şekilde. Tabi burda gözükmeyen trigger, generator gibi bazı kodlar da var ama onlar şimdilik konumuz değil.
CREATE TABLE CARI (
ID INTEGER NOT NULL,
AD VARCHAR(20) COLLATE PXW_TURK,
SOYAD VARCHAR(20) COLLATE PXW_TURK,
BAKIYE NUMERIC(15,2)
);
Tabloyu oluşturduktan sonra programın grafik arayüzünü ve veritabanına bağlantı için gerekli olan bileşenlerimizi ayarlıyoruz. Firebird'e bağlanmak için ben IBX bileşenlerini kullandım.
Yapmak istediğimiz iş Havale yapmak.
Bunun için bize gerekenler bir adet havale yapacak insan, bir adet havale yapılacak insan ve yapılacak olan havale miktarı.
Hepsi bu.
Kullanıcıya bu değerleri girebilmesi/seçebilmesi için ekranda iki adet TDBLookupComboBox ve bir adet TEdit bulunuyor.
DBLookupComboBox1 havale yapacak kişiyi belirtmekle birlikte dfm dosyasındaki kaydı :
object DBLookupComboBox1: TDBLookupComboBox
Left = 136
Top = 18
Width = 225
Height = 21
KeyField = 'ID'
ListField = 'AD;SOYAD'
ListSource = DataSource1
TabOrder = 1
end
DBLookupComboBox2 havale yapılacak kişiyi belirtmekle birlikte dfm dosyasındaki kaydı :
object DBLookupComboBox2: TDBLookupComboBox
Left = 136
Top = 48
Width = 225
Height = 21
KeyField = 'ID'
ListField = 'AD;SOYAD'
ListSource = DataSource1
TabOrder = 2
end
Veritabanı ayarlarına girmiyorum. Sen bunları zaten biliyon Asım.
Şimdi bize bu işi yapacak bir nesne gerekiyor. Aklıma ilk gelen nesne arayüzü aşağıdaki gibi oldu.
HavaleNesnesi.HavaleYapacakKisi -özellik- HavaleNesnesi.HavaleYapilacakKisi -özellik- HavaleNesnesi.HavaleMiktari -özellik- HavaleNesnesi.HavaleIsleminiYap -metod-O zaman Nesnemizi yapmaya başlayalım. Yeni bir Unit oluşturup UnitHavale adında kaydettim. Daha sonra aşağıdaki gibi nesneyi oluşturdum.
type
THavale = class
private
fHavaleYapanCariID :Integer;
fHavaleYapilanCariID :Integer;
fHavaleYapilanMiktar :Double;
function GetHavaleYapanCariID: Integer;
procedure SetHavaleYapanCariID(const Value: Integer);
function GetHavaleYapilanCariID: Integer;
procedure SetHavaleYapilanCariID(const Value: Integer);
function GetHavaleYapilanMiktar: Double;
procedure SetHavaleYapilanMiktar(const Value: Double);
public
Procedure HavaleYap;
property HavaleYapanCariID : Integer
read GetHavaleYapanCariID write SetHavaleYapanCariID;
property HavaleYapilanCariID : Integer
read GetHavaleYapilanCariID write SetHavaleYapilanCariID;
property HavaleYapilanMiktar : Double
read GetHavaleYapilanMiktar write SetHavaleYapilanMiktar;
end;
//
//
HavaleYap proseduru hariç diğer fonksiyon ve prosedurler sadece private veriye ulaşmaya ve değerini set etmeye yaradığından sadece birini yazmam yeterli.
function THavale.GetHavaleYapanCariID: Integer;
begin
Result := fHavaleYapanCariID;
end;
procedure THavale.SetHavaleYapanCariID
(const Value: Integer);
begin
fHavaleYapanCariID := Value;
end;
//
//
İşlemleri tamamladığımıza göre sıra HavaleYap metodunu yazmaya geldi. Lan Asım ! Bu metodda nesnenin hangi veritabanına bilgi ekleyeceği eksik. Niye uyar mıyon? Bunun için nesneye Veritabanı adında TIBDatabase tipinde değer alan bir özellik ekledim.
property Veritabani : TIBDatabase read GetVeritabani write SetVeritabani;Şimdi HavaleYap metodunu yazabiliriz.
procedure THavale.HavaleYap;
begin
IBSqlOlustur;
if fibsql.Transaction.InTransaction = False Then
fibsql.Transaction.StartTransaction;
try
try
fibsql.Close;
fibsql.SQL.Clear;
fibsql.SQL.Add('Update CARI set BAKIYE = BAKIYE + ' +
FloatToStr(HavaleYapilanMiktar));
fibsql.SQL.Add('Where ID =' +
IntToStr(HavaleYapilanCariID));
fibsql.ExecQuery;
fibsql.Close;
fibsql.SQL.Clear;
fibsql.SQL.Add('Update CARI set BAKIYE = BAKIYE - ' +
FloatToStr(HavaleYapilanMiktar));
fibsql.SQL.Add('Where ID =' +
IntToStr(HavaleYapanCariID));
fibsql.ExecQuery;
fibsql.Transaction.CommitRetaining;
except
fibsql.Transaction.RollbackRetaining;
Raise Exception.Create
('Dikkat!!! Havale işlemi başarılı olamadı...');
end;
finally
IBSqlYokEt;
end;
end;
procedure THavale.IBSqlOlustur;
begin
if not Assigned(fIBDatabase) Then
Raise Exception.Create
('Bağlanılacak Veritabanı bulunamadı. İşlem iptal ediliyor !!!');
if Assigned(fibsql) Then Exit;
fIbSql := TIBSQL.Create(nil);
fIbSql.Database := Veritabani;
fIbSql.Transaction := Veritabani.DefaultTransaction;
end;
procedure THavale.IBSqlYokEt;
begin
FreeAndNil(fibsql);
end;
//
//
Şimdi işlemi gerçekleştirecek olan düğmenin click olayına ilgili kodumuzu yazalım.
procedure TForm1.btnHavaleYapClick(Sender: TObject);
var
Havale :THavale;
begin
Havale :=THavale.Create;
try
Havale.Veritabani :=IBDatabase1;
Havale.HavaleYapanCariID :=DBLookupComboBox1.KeyValue;
Havale.HavaleYapilanCariID :=DBLookupComboBox2.KeyValue;
Havale.HavaleYapilanMiktar :=StrToFloat(edit1.Text);
Havale.HavaleYap;
ShowMessage('Havale Başarılı');
finally
FreeAndNil(Havale);
end;
end;
//
//
Programı çalıştırıyoruz ve listelerden uygun kişileri seçip havale miktarını da yazdıktan sonra Havale Yap düğmesine tıkladığımız zaman havale işlemini yapıyoruz. Ardından veritabanına gözatarak işlemin doğru olup olmadığını kontrol ediyoruz.
Gayet başarılı :)
Asım: Sistem iyi güzel çalışıyo da biz neden böyle bir şey yaptık. Havale Yap butonuna aşağıdaki kodları yazsak bizim işimizi görmez mi ? Neden THavale adında bi nesne tanımlayıp 170 - 20 = 150 satır daha fazladan kod yazdık ? Ne kadar kod, o kadar kafa karışıklığı demek değil mi?
procedure TForm1.btnHavaleYapClick(Sender: TObject);
begin
try
IBSQL1.Close;
IBSQL1.SQL.Clear;
IBSQL1.SQL.Add('Update CARI set BAKIYE = BAKIYE +
' + edit1.Text);
IBSQL1.SQL.Add('Where ID =' +
IntToStr(DBLookupComboBox1.KeyValue));
IBSQL1.ExecQuery;
IBSQL1.Close;
IBSQL1.SQL.Clear;
IBSQL1.SQL.Add('Update CARI set BAKIYE = BAKIYE - ' +
Edit1.Text);
IBSQL1.SQL.Add('Where ID =' +
IntToStr(DBLookupComboBox2.KeyValue));
IBSQL1.ExecQuery;
IBSQL1.Transaction.CommitRetaining;
except
IBSQL1.Transaction.RollbackRetaining;
Raise Exception.Create
('Dikkat!!! Havale işlemi başarılı olamadı...');
end;
end;
//
//
Asım, böyle yazacaksın. Nesneye dayalı yazılım diyosan al sana nesne işte. Bu kodu butona yazacan da ne olacak ? İki gün sonra başka bi formdan tekrar havale yapmak istersen ne olacak? Burdaki kodu alıp oraya mı yapıştıracan ? Hadi sen neysende senden sonra bu programın gelişimini devam ettirecek çaylağın BAKIYE = BAKIYE * MIKTAR gibi bi kod yazmayacağını garanti edebilir misin? Böyle ulu orta yere serpilmiş bir kodla Teste dayalı yazılım nasıl geliştireceksin ayıptır sölemesi ? Birçok yerden havale yaptığın vakit, havale işleminde meydana gelecek bi değişikliği programa nasıl yansıtacan ? Butonlara yazdığın iki kodu şöyle bir karşılaştırdığında hangisi daha anlaşılır, hataya yapma olasılığı daha az ve kolay okunabilir ? Aldırma elime karamiş sopasını Asım ! :)
Devam ediyoruz...
Günün birinde yetkili amcam geldi ve "Sistemde açık var. Bakiyesinde yeterli miktarda parası olmayan kişi havale yapabiliyor?. Bu nasıl bir iş ? Sen nasıl bir programcısın?" diye bize fırçayı attı. Altında kalma. Ver cevabını. (Bu senin işten atılmana engel olmuyorsa tabi) "Ne kızıyon yaw ? Yaparız iki dakka da" dedin ve işe koyuldun.
Nesnemizin bulunduğu uniti açıp değişiklik yapcaz. Hepsi bu. Sonra programı yeniden derleyecez. Sonra programı bankadaki tüm memurların bilgisayarına yeniden yükleyecez. (mi acaba ? Nesneye dayalı yazılım, dağıtık uygulamalarda da çok önemli Asım)
Nesnemizin Private alanına
Function HavaleYapacakKisininYeterliBakiyesiVarmi:Boolean; adlı bi fonksiyon ekledik. Bu fonksiyonun nesnemizi kullanan kişiler tarafından görünmesini istemiyoruz çünkü. Bu da nesnenin gövdesi :
function
THavale.HavaleYapacakKisininYeterliBakiyesiVarmi: Boolean;
begin
fIbQuery := TIBQuery.Create(nil);
try
Result := False;
fIbQuery.Database := fIbSql.Database;
fIbQuery.Transaction := fIbSql.Transaction;
fIbQuery.Close;
fIbQuery.SQL.Clear;
fIbQuery.SQL.Add('Select BAKIYE FROM CARI WHERE ID =' +
IntToStr(HavaleYapanCariID));
fIbQuery.Open;
Result := fIbQuery.Fields[0].AsFloat -
HavaleYapilanMiktar >= 0.00;
finally
FreeAndNil(fIbQuery);
end;
end;
//
//
Sonra havale yap prosedurune bunu ekliyoruz.
procedure THavale.HavaleYap;
begin
IBSqlOlustur;
if HavaleYapacakKisininYeterliBakiyesiVarmi = False Then
Raise Exception.Create
('İşlem yapacak kişinin bakiyesi yeterli değil. İşlem iptal ediliyor !!!');
if fibsql.Transaction.InTransaction = False Then
fibsql.Transaction.StartTransaction;
...
...
//
//
İşimiz bitti...
Müdür : - Hişt aloooo! Napıyonuz lan orda siz ikiniz ? Yine ogame ' mi oynuyonuz ?
Asım : - Yok patron ! Sadece grafiklerini inceliyoduk.
Müdür : - Yaw benim biraz metale ihtiyacım var. Bi nakliye çıkartsanız bana. He !
Asım : - Valla olsa dükkan senin müdür bey.
Müdür : - Neyse ben buraya size bişe sölemek için geldim. Bundan sonra Havale yapan kişiden havale ücretinin % 1'i kesilecek.
Hadi bir an önce yapın şunu.
Asım : (Yaw tam da filoyu saldırıya göndermiştim. hay allah) - Tamam müdür bey.
...
...
private
fHavaleYapanCariID :Integer;
fHavaleYapilanCariID :Integer;
fHavaleYapilanMiktar :Double;
fIBDatabase :TIBDatabase;
fIbSql : TIBSQL;
fHavaleUcreti : Double; // yeni eklenen satır
...
...
HavaleYap Proseduru
...
...
fHavaleUcreti := HavaleYapilanMiktar / 100;
fibsql.Close;
fibsql.SQL.Clear;
fibsql.SQL.Add('Update CARI set BAKIYE = BAKIYE - '+
FloatToStr(HavaleYapilanMiktar +
fHavaleUcreti));
fibsql.SQL.Add('Where ID =' +
IntToStr(HavaleYapanCariID));
fibsql.ExecQuery;
...
...
...
//
İşlem tamam abi.
Yorumlar
fibsql.Close;
fibsql.SQL.Clear;
fibsql.SQL.Add('Update CARI set BAKIYE = BAKIYE + :P_BAKIYE' );
fibsql.SQL.Add('Where ID = :P_CARIID');
fibsql.Params[0].AsFloat := HavaleYapilanMiktar;
fibsql.Params[1].AsInteger := HavaleYapilanCariID;
fibsql.ExecQuery;
fHavaleUcreti := HavaleYapilanMiktar / 100;
fibsql.Close;
fibsql.SQL.Clear;
fibsql.SQL.Add('Update CARI set BAKIYE = BAKIYE - :P_BAKIYE');
fibsql.SQL.Add('Where ID = :P_CARIID');
fibsql.Params[0].AsFloat := HavaleYapilanMiktar - fHavaleUcreti;
fibsql.Params[1].AsInteger := HavaleYapanCariID;
fibsql.ExecQuery;
-Nasıl hatalar abi ?
-Kodu şu şekilde yazdığımızı düşün. bunun sonucu ne olur ?
procedure TForm1.btnHavaleYapClick(Sender: TObject);
var
Havale :THavale;
begin
Havale :=THavale.Create;
try
Havale.Veritabani :=IBDatabase1;
Havale.HavaleYapanCariID :=DBLookupComboBox1.KeyValue;
Havale.HavaleYapilanCariID :=DBLookupComboBox2.KeyValue;
Havale.HavaleYapilanMiktar :=StrToFloat(edit1.Text);
Havale.HavaleYap;
ShowMessage('1. Havale Başarılı');
//başka bir veritabanında da aynı işlemi yapmak istiyoruz. ibdatabase2
Havale.Veritabani :=IBDatabase2;
Havale.HavaleYapanCariID :=DBLookupComboBox1.KeyValue;
Havale.HavaleYapilanCariID :=DBLookupComboBox2.KeyValue;
Havale.HavaleYapilanMiktar :=StrToFloat(edit1.Text);
Havale.HavaleYap;
ShowMessage('2. Havale de Başarılı');
finally
FreeAndNil(Havale);
end;
end;
- 2. havale başarılı olabilir mi Asım ?