Konuyu Oyla:
  • Derecelendirme: 4/5 - 1 oy
  • 1
  • 2
  • 3
  • 4
  • 5
Veritabanı güncelleme
#1
Merhaba arkadaşlar,

Projemde güncelleme yapmak istiyorum. 
Exe güncellememi ftp üzerinden yapacağım ayrıca veritabanını da güncellemek istiyorum otomatik olarak.

Yani
Exe mi kullanan kişi Exe yi çalıştırdığında exe'de / Db de güncellensin.

Örneğin:

DB_VERSIYON 1 de OgrenciTablo su içerisinde (DB_VERSIYON1  , EXE_VERSIYON1 ILE UYUMLU)
ogrenciTablosu
Isim        Nvarchar(50)
Soyisim   Nvarchar(50)
Numara  Integer

DB_VERSIYON2 de OgrenciTablosu içerisinde (DB_VERSIYON2  , EXE_VERSIYON2 ILE UYUMLU)
ogrenciTablosu
Isim        Nvarchar(100)
Soyisim   Nvarchar(50)
Numara  Integer
Tckn      Nvarchar(11)

Aradaki fark
-İsim kolonu boyutu artırıldı
-Tckn kolonu eklendi.

Ben en son olarak EXE2 yi yayınladım. Sistemimi güncellerken ikisini de güncellemek istiyorum.
Umarım anlatabilmişimdir.
Bunu nasıl yapabilirim , tavsiyesi olan var mı? bilgisi olan arkadaşlar yardım edebilir mi?


Teşekkürler
Cevapla
#2
Merhaba.

- Eski EXE yerine yenisini çalıştırmak işi kullanıcı tarafında gerçekleşecek bir durum. 

- Asıl mesele kullanıcının bilgi ve deneyimi ile orantılı olarak ilerleyen zamanlarda yedek/kurtarma vb. ile yeniden daha eski bir sürüme geçip geçmediğinin kontrolüdür. 

- Ben bunu veritabanındaki (iki) anahtar alan ile baştan hallediyorum. Yani kullanılan EXE sürümü veritabanı ile karşılaştırılıyor. Eski sürüm ise önce kullanıcıya sonra da eposta/sms ile bana bilgi geliyor. 

- iki anahtar alan derken birisi güncel olması gereken sürüm, ikincisi de veritabanına / veri girişine zararı olmayan en eski sürüm numarası oluyor. Yani bir sürümde ekran tasarımında, menü geçişlerinde ya da veri tabanında sadece alan boyutu değiştirmişsem veya süreci etkilemeyecek ekstra bir alan eklemişsem ( null kalmasında sakınca olmayan türden ) fahiş hata oluşturmayacağından bir önceki sürüm çalışsa da sadece uyarı ile daha az acil olarak değerlendiriyorum. Ama yine de kayıtsız kalmayıp süpervizör ile kullanıcıyı karşı karşıya getirmek üzere altyapı çalışıyor. 

- Veri tipi değişmiş veya sürecin yönünü değiştirecek türden ise güncelleme, o zaman olmazsa olmaz deyip exe'nin çalışmasına otomatik olarak son veriyor, kullanıcıyı yeni sürüm bulunan lokasyona veya süpervizöre yönlendiriyorum. 

- Tablo güncelleme için SQL komutları ile yapabilirsiniz. Idea

Örneğin 
ALTER TABLE ogrenciTablosu ALTER COLUMN isim Nvarchar(100)

ALTER TABLE ogrenciTablosu ADD COLUMN Tckn Nvarchar(11)

Son Not: Kendi projelerimde mümkünse ağ altında TCP portarından birinden bir sunucudaki ana kontrol projesi (LOG tutar vs. ) ile irtibatı daima sağlıyorum. Kontrol dışı erişim, sürüm ihlali vb. durumlarda EXE projenin merkezi olarak kapatılması imkanım da daima el altında oluyor. 

Ama yine de eski EXE'nin kapatılması için 

(1) Yeni EXE çalıştığında önce hafızada eski EXE var olup olmadığını WinApi'leriyle tespit edip
(2) Çalışan EXE'nin adını RENAME edip
(3) Aynı EXE konumuna yeni EXE'yi kopyalayıp
(4) Hafızada çalışan eski EXE'yi Terminate edip
(5) Yeni EXE'yi çalıştırmak

ile çalışır haldeki eski EXE'nin sonlandırılıp yerine yeni EXE'nin çalışmasını sağlayabilirsiniz.
Saygılarımla
Muharrem ARMAN

guplouajuixjzfm15eqb.gif
Cevapla
#3
SQL tarafında bir önerim şöyle olabilir size.
Değişiklik yaptığınız tablonun
Alter Cümesini bir tabloya yazın.
orada ID ye göre ister tarihe göre kontrol edecek bir Triger yazarsınız.
Clientler her zaman o Merkez sunucudaki tabloyu kontrol ederler eğer orada yeni bir işlem varsa triger oto çalışacaktır ve Clientteki SQL tablolarını Güncelleyecektir.
Cevapla
#4
Alterlari çalıştırın exeyi kullanan kullanicilar olabileceği için isminin sonuna örnek _ ekleyin yeni exeyi atın kullanicilar sistemden düşmez bir sonraki loginde yeni exe ile devam edeceklerdir
Cevapla
#5
(14-06-2018, Saat: 12:25)mrmarman Adlı Kullanıcıdan Alıntı: Merhaba.

- Eski EXE yerine yenisini çalıştırmak işi kullanıcı tarafında gerçekleşecek bir durum. 

- Asıl mesele kullanıcının bilgi ve deneyimi ile orantılı olarak ilerleyen zamanlarda yedek/kurtarma vb. ile yeniden daha eski bir sürüme geçip geçmediğinin kontrolüdür. 

- Ben bunu veritabanındaki (iki) anahtar alan ile baştan hallediyorum. Yani kullanılan EXE sürümü veritabanı ile karşılaştırılıyor. Eski sürüm ise önce kullanıcıya sonra da eposta/sms ile bana bilgi geliyor. 

- iki anahtar alan derken birisi güncel olması gereken sürüm, ikincisi de veritabanına / veri girişine zararı olmayan en eski sürüm numarası oluyor. Yani bir sürümde ekran tasarımında, menü geçişlerinde ya da veri tabanında sadece alan boyutu değiştirmişsem veya süreci etkilemeyecek ekstra bir alan eklemişsem ( null kalmasında sakınca olmayan türden ) fahiş hata oluşturmayacağından bir önceki sürüm çalışsa da sadece uyarı ile daha az acil olarak değerlendiriyorum. Ama yine de kayıtsız kalmayıp süpervizör ile kullanıcıyı karşı karşıya getirmek üzere altyapı çalışıyor. 

- Veri tipi değişmiş veya sürecin yönünü değiştirecek türden ise güncelleme, o zaman olmazsa olmaz deyip exe'nin çalışmasına otomatik olarak son veriyor, kullanıcıyı yeni sürüm bulunan lokasyona veya süpervizöre yönlendiriyorum. 

- Tablo güncelleme için SQL komutları ile yapabilirsiniz. Idea

Örneğin 
ALTER TABLE ogrenciTablosu ALTER COLUMN isim Nvarchar(100)

ALTER TABLE ogrenciTablosu ADD COLUMN Tckn Nvarchar(11)

Son Not: Kendi projelerimde mümkünse ağ altında TCP portarından birinden bir sunucudaki ana kontrol projesi (LOG tutar vs. ) ile irtibatı daima sağlıyorum. Kontrol dışı erişim, sürüm ihlali vb. durumlarda EXE projenin merkezi olarak kapatılması imkanım da daima el altında oluyor. 

Ama yine de eski EXE'nin kapatılması için 

(1) Yeni EXE çalıştığında önce hafızada eski EXE var olup olmadığını WinApi'leriyle tespit edip
(2) Çalışan EXE'nin adını RENAME edip
(3) Aynı EXE konumuna yeni EXE'yi kopyalayıp
(4) Hafızada çalışan eski EXE'yi Terminate edip
(5) Yeni EXE'yi çalıştırmak

ile çalışır haldeki eski EXE'nin sonlandırılıp yerine yeni EXE'nin çalışmasını sağlayabilirsiniz.

Anladım. Teşekkürler hocam.
Ben scriptleri yazmak yerine benim yerime veri tabanındaki scriptleri yazan bir şey istiyorum =)
Delphi de böyle birşey yapılabilir mi? 
Veritabanındaki tabloları - tabloların kolonlarını - kolonlarının özelliklerini karşılaştırıp misalen eksik bir durum oldugunda kendisi tamamlayacak şekilde
Cevapla
#6
Kendi projelerimde kullandığım bir yapı var.
Tablo ve Field kontrol fonksiyonları.

Projelerimde Table Create için Table Structure ( create table sql kalıpları ) kullanıyorum. 

Bu kalıbı field kontrol fonksiyonuna verince, kalıbı kendim verdiğim için kolayca text sql parse ederek, ardından da mevcut fiziki tablonun da field özelliklerini alıp deşifre ile elde edilen güncel tablo yapısı ile karşılaştırabiliyorum. 

Ancak komplike bir yapı olduğunu tahmin edersiniz.
Saygılarımla
Muharrem ARMAN

guplouajuixjzfm15eqb.gif
Cevapla
#7
ORM tooları istediğiniz işlemi çözebilir sanırım. Şurada bir kaç tane ORM den bahsedilmiş.
WWW
Cevapla
#8
Muharrem hocam Teşekkürler..

Hakan Uçar inceleyim miüsait zamanımda dönüş yapacağım
Cevapla
#9
Merhaba.

Direk bir şey ifade etmeyebilir ancak bahsetmek istediğim işlem için fikir oluşması açısından bir örnek.  

NOT: Bunu bir sınıfa dönüştürebilirsem ayrıca paylaşırım. Geniş ve rahat bir zamana ihtiyaç var. Kendi planlarımda bu var. Hem de kodlarıma bir çeki düzen vermiş olacağım.


1. Tablo eksik mi kontrolü. Eksikse CREATE TABLE structure kalıbı çalışır.  Yeni bir müşteri ise müşteriye özel sıfır km. tablolar bu sayede oluşur.

2. Tablo tamam ama alan eksikse alan ekleme işlemi yapılır.

3. Alan var ama boyutu farklı ise alan resize edilir.

4. AutoInc alan kontrolü yapılır. Var olan bir alan AutoInc şekle dönüşecek ise NULL veye tekrar eden kayıtlardan kurtulmak gerekir. Bu işlemler de otomasyonda yer alır.

5. Son olarak indexler kontrol edilir. 

Aşağıda bu saydıklarımdan sadece ilk üçünü göreceksiniz. Dediğim gibi çok komplike bir yapı ister.

Global Sabit
const
 TabloList: array[00..08] of string = (  'URUN'
                                       , 'URUNTANIM'
                                       , 'TIPTANIM'
                                       , 'PERSONEL'
                                       , 'ZIMMETHAREKET'
                                       , 'URUNGRUBU'
                                       , 'URUNGRUBUHAREKET'
                                       , 'ENVANTERKAT'
                                       , 'ARIZAFORM'
                                      );


Mekanizmanın Dışı

Procedure tStokHelper.aZExecute( aScript : String );
begin
 With TZConnection.Create(nil) do begin
   Try
     Protocol    := 'ado';
     LoginPrompt := False;
     DataBase    := FZConnection.DataBase;
     Connected   := True;
     Try
     ExecuteDirect( aScript );
     Except
       if FMemo <> nil then
       begin
         FMemo.Lines.Add( '**********' );
         FMemo.Lines.Add( aScript );
       end;
     End;
   Finally
     Connected  := False;
     Free;
   End;
 end;
end;

procedure tStokHelper.TablolarKontrol(strDatabase: String; IndexTazele:Boolean);
Var
 Struc,
 Liste       : TStringList;
 Sayac       : Integer;
 IDXList     : TstringList;
 i           : Integer;
begin
 Liste := TStringList.Create;

 if NOT FZConnection.Connected then begin
   FZConnection.Connected        := False;
   FZConnection.Database         := Format( xBaglanti,[strDatabase] );
   FZConnection.LoginPrompt      := False;
   FZConnection.Protocol         := 'ado';
   FZConnection.Connected        := True;
 end;
 FZConnection.GetTableNames( '', Liste );

 Struc := TStringList.Create;
 For Sayac := low(TabloList) to High(TabloList) do
 begin
   Struc.Text := '';
   If Liste.IndexOf( TabloList[Sayac] ) < 0 then begin
     case Sayac of
       00: StrucOlustur_Urun             (Struc);
       01: StrucOlustur_UrunTanim        (Struc);
       02: StrucOlustur_TipTanim         (Struc);
       03: StrucOlustur_Personel         (Struc);
       04: StrucOlustur_ZimmetHareket    (Struc);
       05: StrucOlustur_UrunGrubu        (Struc);
       06: StrucOlustur_UrunGrubuHareket (Struc);
       07: StrucOlustur_EnvanterKat      (Struc);
       08: StrucOlustur_ArizaForm        (Struc);
     end; // Case

     if Struc.Text <> '' then
     begin
       aZExecute( Struc.Text );
     end else showmessage( '"'+TabloList[Sayac] + '" Tablosu için Table Structure bulunamadı...' );
   end
   else begin
     FieldKontrol( strDatabase, TabloList[Sayac] );
   end;

   If IndexTazele THEN
   begin
     IDXList       := TStringList.Create;
     With TZSQLMetadata.Create(nil) do begin
       Try
         Connection   := FZConnection;
         MetadataType := mdIndexInfo;
         TableName    := TabloList[Sayac];
         Active       := True;
         while not Eof do begin
           if IDXList.IndexOf( FieldByName('INDEX_NAME').AsString ) < 0
             then IDXList.Add( FieldByName('INDEX_NAME').AsString );
           Next;
         end;
       Finally
         Close;
         Free;
       End;
     end;

     for i := 0 to IDXList.Count - 1
     do aZExecute( 'DROP INDEX '+IDXList[i] + ' ON '+TabloList[Sayac] );

     IDXList.Free;

     case Sayac of
       00: IndexOlustur_Urun             ();
       01: IndexOlustur_UrunTanim        ();
       02: IndexOlustur_TipTanim         ();
       03: IndexOlustur_Personel         ();
       04: IndexOlustur_ZimmetHareket    ();
       05: IndexOlustur_UrunGrubu        ();
       06: IndexOlustur_UrunGrubuHareket ();
       07: IndexOlustur_EnvanterKat      ();
       08: IndexOlustur_ArizaForm        ();
     else showmessage( TabloList[Sayac] + ' Tablosu için Index Structure bulunamadı...' );
     end; // Case
   end;
 end;

 if IndexTazele then
 begin // Son olarak bir de AutoInc alanları tamir edelim..
   AutoIncAlanlariTamirEt();
 end;

 Struc.Free;
 Liste.Free;
end;

Structure Kalıbı Örneği
Procedure  StrucOlustur_Urun( KomutListesi : TStrings );
Const
 FieldTanimi     = '%s %s(%d),';
 FieldTanimiDate = '%s %s,';
begin
{ --- Table Structure --- }
 With KomutListesi do
 begin
   Clear;
   Add( 'CREATE TABLE URUN(');
   Add( Format(FieldTanimiDate, ['U_KaySiraNo'       ,'AutoIncrement',    0  ] ) );
   Add( Format(FieldTanimiDate, ['U_UT_KaySiraNo'    ,'Numeric',          0  ] ) );
   Add( Format(FieldTanimi,     ['U_SeriNo'          ,'Text',           150  ] ) );
   Add( Format(FieldTanimi,     ['U_DemirNo'         ,'Text',           150  ] ) );
   Add( Format(FieldTanimi,     ['U_Aciklama'        ,'Text',           255  ] ) );
   Add( Format(FieldTanimi,     ['U_AciklamaEN'      ,'Text',           255  ] ) );
   Add( Format(FieldTanimiDate, ['U_GirTar'          ,'Date',             0  ] ) );
   Add( Format(FieldTanimiDate, ['U_HekTar'          ,'Date',             0  ] ) );
   Add( Format(FieldTanimiDate, ['U_TerkTar'         ,'Date',             0  ] ) );
   Add( Format(FieldTanimi,     ['U_TerkAciklama'    ,'Text',           150  ] ) );
   Add( Format(FieldTanimiDate, ['U_Silindi'         ,'Logical',          0  ] ) );
   Add( Format(FieldTanimiDate, ['U_Secim'           ,'Logical',          0  ] ) );
   Add( Format(FieldTanimiDate, ['U_Kontrol'         ,'Logical',          0  ] ) );
   Add( Format(FieldTanimi,     ['U_UNIQID'          ,'Text',            50  ] ) );
   Add( Format(FieldTanimiDate, ['U_Gecici'          ,'Logical',          0  ] ) );
   Add( Format(FieldTanimiDate, ['U_AtaKarneli'      ,'Logical',          0  ] ) );
   Add( Format(FieldTanimiDate, ['U_MasterKayno'     ,'Numeric',          0  ] ) );
   Add( Format(FieldTanimi,     ['U_BarCode'         ,'Text',            50  ] ) );
   Add( Format(FieldTanimi,     ['U_RFIDTag'         ,'Text',            50  ] ) );

   Add( Format(FieldTanimi,     ['U_KurumdakiAdi'    ,'Text',           255  ] ) );
   Add( Format(FieldTanimiDate, ['U_GirFiyat'        ,'Currency',         0  ] ) );
   Add( Format(FieldTanimiDate, ['U_SonFiyatTar'     ,'Date',             0  ] ) );
   Add( Format(FieldTanimiDate, ['U_SonFiyat'        ,'Currency',         0  ] ) );
   KomutListesi[KomutListesi.Count-1] := Copy(KomutListesi[KomutListesi.Count-1], 1, Length(KomutListesi[KomutListesi.Count-1])-1); {Son Virgülü Attık}
   Add( ')');
 end;
end;

Field Kontrol / Alan Ekle / Resize Fonksiyonları 
Procedure tStokHelper.FieldCheck(strDatabase, Tablo: String; Struc:TStringList);
Var
 Sayac     : Integer;
 sDummy, Alan, Tip : String;
 Uz        : Integer;
 i         : Integer;

 aTip      : String;
 Gecici    : String;

 EksikField  : TStringList;
 DuzeltField : TStringList;
begin
 // Structure Parse edilerek
 // ------------------------
 //  1. Eksik alan varsa eklenir.
 //  2. Uzunluk değişikliği yapılmışsa güncellendir.
 //  3. Tip değişikliği yapılmışsa

 EksikField  := TStringList.Create;
 DuzeltField := TStringList.Create;
 try
   With TZQuery.Create(Nil) do
   begin
     Connection := FZConnection;
     SQL.Text   := 'SELECT * FROM ' + Tablo;
     Active     := True;
     For Sayac := 1 to Struc.Count-2 do  // 0 ncı satırda "Create Table" var...
                                         // Son Satırda ")" var...
     begin
       Alan   := '';
       Tip    := '';
       Uz     := 0;
       Gecici := Trim(Struc[Sayac]);

       If Gecici[Length(Gecici)] <> ',' then Gecici := Gecici + ','; // Afrikda Fil arar gibi.. Smile
       Alan := Copy(Gecici, 1, Pos(' ', Gecici)-1);

       System.Delete( Gecici, 1, Length(Alan) );
       Gecici := Trim(Gecici);

       Tip  := Gecici;
         If Copy( Tip, 1, Pos('(', Tip)-1 ) <> ''
           then Tip := Copy( Tip, 1, Pos('(', Tip)-1 )
           else Tip := Copy( Tip, 1, Pos(',', Tip)-1 );

       System.Delete( Gecici, 1, Length(Tip) );
       Gecici := Trim(Gecici);

       If ( Gecici <> '' ) AND ( Gecici[1] = '(' )
         then Uz := StrToInt(Copy(Gecici, 2, Pos(')', Gecici)-2));

       If FieldList.IndexOf(Alan) < 0 then
       begin
         EksikField.Add( Format('%s|%s|%d|', [ Alan, Tip, Uz ] ) );
       end else
       begin
         If (FieldByName(Alan).Size <> Uz)
           then begin
             AlanResize( Tablo, Alan , Tip, Uz)
           end
           else
           begin
             aTip := '';
             case FieldByName(Alan).DataType of
             ftAutoInc : aTip := 'AutoIncrement';
             ftString  : aTip := 'Text';
             ftInteger : aTip := 'Integer';
             ftBoolean : aTip := 'Logical';
             ftDate    : aTip := 'Date';
             ftTime    : aTip := 'Time';
             ftMemo    : aTip := 'Memo';
             end;

             If (aTip <> '') AND ( UpperCase(aTip) <> UpperCase(Tip) ) then
             begin
               if UpperCase(Tip) <> 'AUTOINCREMENT' then
               begin // 'INTEGER' ile 'AUTOINCREMENT' karıştırılıyor...
                 DuzeltField.Add( Format('%s|%s|%d|', [ Alan, Tip, Uz ] ) );
               end;
             end;
           end;
       end;
     end;
     Active := False;
     Free;
   end; // With

   if EksikField.Count > 0 then begin
     For i := 0 to EksikField.Count-1 do
     begin
       sDummy := EksikField[i];
       Alan := Copy( sDummy, 1 , Pos('|', sDummy)-1);
         system.Delete( sDummy, 1, Pos('|', sDummy) );
       Tip  := Copy( sDummy, 1 , Pos('|', sDummy)-1);
         system.Delete( sDummy, 1, Pos('|', sDummy) );
       Uz   := StrToInt( Copy( sDummy, 1 , Pos('|', sDummy)-1) );
       AlanEkle( Tablo, Alan, Tip, Uz);
     end;
   end;

   if DuzeltField.Count > 0 then begin
     For i := 0 to DuzeltField.Count-1 do
     begin
       sDummy := DuzeltField[i];
       Alan := Copy( sDummy, 1 , Pos('|', sDummy)-1);
         system.Delete( sDummy, 1, Pos('|', sDummy) );
       Tip  := Copy( sDummy, 1 , Pos('|', sDummy)-1);
         system.Delete( sDummy, 1, Pos('|', sDummy) );
       Uz   := StrToInt( Copy( sDummy, 1 , Pos('|', sDummy)-1) );
       AlanResize( Tablo, Alan, Tip, Uz);
     end;
   end;
 finally
   EksikField.Free;
 end;
end;

Procedure tStokHelper.AlanEkle( Tablo: String; Alan, Tip : String; Uzunluk:Integer );
Const
  FieldEkle       = 'ALTER TABLE %s ADD %s %s(%d)';
  FieldEkleDate   = 'ALTER TABLE %s ADD %s %s';
begin
  Case Uzunluk of
  0:   aZExecute( Format(FieldEkleDate, [Tablo, Alan, Tip ]) );
  else aZExecute( Format(FieldEkle,     [Tablo, Alan, Tip, Uzunluk ]) );
  end; // Case
end;

Procedure tStokHelper.AlanResize( Tablo: String; Alan, Tip : String; Uzunluk:Integer );
Const
  FieldEkle     = 'ALTER TABLE %s ALTER COLUMN %s %s(%d)';
  FieldEkleDate = 'ALTER TABLE %s ALTER COLUMN %s %s';
begin
  Case Uzunluk of
  0:   aZExecute( Format(FieldEkleDate, [Tablo, Alan, Tip ]) );
  else aZExecute( Format(FieldEkle,     [Tablo, Alan, Tip, Uzunluk ]) );
  end; // Case
end;

Saygılarımla
Muharrem ARMAN

guplouajuixjzfm15eqb.gif
Cevapla
#10
Açıklayıcı anlatım için teşekkürler hocam.

Aynen dediğiniz gibi olmasını istiyorum. Yani müşterideki veri tabanını exe nin kullanacağı biçimde dataları bozmadan düzenlemek
Cevapla


Konu ile Alakalı Benzer Konular
Konular Yazar Yorumlar Okunma Son Yorum
  server programinda hani veritabani dogru olur. sadikacar60 4 345 30-01-2024, Saat: 21:06
Son Yorum: sadikacar60
  COZULDU veritabani prg yerine ne kullanabilirim. sadikacar60 8 776 29-01-2024, Saat: 18:41
Son Yorum: sadikacar60
  Serverda bulunan kullanıcıların exelerini guncelleme mertnas 20 1.823 13-11-2023, Saat: 11:31
Son Yorum: shooterman
  SQL VeriTabanı Kopyalama Hk. glagher 4 618 10-09-2023, Saat: 14:18
Son Yorum: glagher
  Veritabanı FireDAC, Zeos, UniDAC kıyaslaması nguzeller 0 345 08-07-2023, Saat: 00:28
Son Yorum: nguzeller



Konuyu Okuyanlar: 1 Ziyaretçi