1 Son düzenleyen, soykanozcelik (08.11.2006 12:53:05)

Konu: SPT - SQL Pass Through ile SQL Servera baglanti class i

asagida kodlarini yayinladigim class kodlari ile SQL Pass Through yöntemi ile SQL servera baglanma yöntemi için başlangic olacak ornekleme yaptim bu tip bir class ile ister sorgu formlari ister data isleme formlarinizda ornekledigimin daha fazlasini yapabilirsiniz.

Umarım faydalı olur

* class icin kaynak olarak EPS software kodlarindan faydalandim ve kendime göre cesitli modifiyeler yaptim. en pratik olani updatelist ler icin işi afields() ile vfp ye birakiyor olmak :) ve tüm olayi propertyler sayesinde halletmek. Bu sayede bircok kodlama angaryasindan kurtulabiliyorsunuz ancak
deneyimsiz kullanicilar icin daha öncede bahsi gecmisti RV (remote view) yada CA (cursoradapter) daha kolay gelebilir . Hoş bende SQL e yavaş yavaş ısınyorum ama CA ve SPT arasında gidip gelecegim gibi gözüküyor :)


Visual Fox Pro
&& Class:        stb_spt_sql_connector (d:\soykan\mysoftware\emin_elk\lib\soykan.vcx)

&& ParentClass:  custom
&& BaseClass:    custom
&& Time Stamp:   11/08/06 02:04:08 AM
&&
Define Class stb_spt_sql_connector As Custom
 
&&server a baglanti
    nhandle = 0
&&baglanilacak server adi
    cservername = []
&&baglanilacak database adi
    cdatabasename = []
&&baglanilacak tableadi
    ctablename = []
&&primary key column adi
    ckeyfield = []
&login ekrani gozuksunmu
    nhold_displogin = 0
&& baglanti asim suresi
    nhold_connecttimeout = 0
&& isletilecek kod
    cexecstring = []
&& olusacak cursor adi
    ccursor = []
&& SQL baglanti cumlesi
    cconnectstring = []
&& .t. ise her sql baglantidan sonra baglantiyi kesme
    lpersistconnection = .T.
&& isletim sistemi 2000,xp ise trusted_conn secin
    ltrustedconnection = .T.
&& baglantida updatable cursor kullanilacakmi
    isupdatable = .f.
&& kullanici adi
    cuid = []
&& kullanici sifresi
    cpassword = []
    Name = "stb_spt_sql_connector"
 
&& execute method
    Procedure execute
    Local lnError
    lnError = 0
&& sql cumlesi yoksa birsey yapma
    If Empty(This.cexecstring)
        Return .F.
    Endif
    With This
        lnError = SQLExec(.nhandle, .cexecstring, .ccursor)
        If lnError < 0 && hata yakalama kismi
            .displayerror()
            _Cliptext = .cexecstring
        Endif
        Assert lnError > 0 Message "Error executing SQL command."
        If Not .lpersistconnection
            .Disconnect()
        Endif
    Endwith
    Return Type("lnError")="N" And lnError > 0
    Endproc
 
&& connect method
    Procedure Connect
    Local lnResult
&& gizli olursa daha iyi olur (protected)
    With This
        If .ltrustedconnection
            .cconnectstring = "DRIVER=SQL Server" + ;
                ";SERVER=" + .cservername + ;
                ";DATABASE=" + .cdatabasename + ;
                ";Trusted_Connection=Yes"
        Else
            .cconnectstring = "DRIVER=SQL Server" + ;
                ";SERVER=" + .cservername + ;
                ";DATABASE=" + .cdatabasename + ;
                ";UID=" + .cuid + ;
                ";PWD=" + .cpassword
        Endif
        This.nhandle = Sqlstringconnect(.cconnectstring)
    Endwith
    Endproc
 
&& disconnect method
    Procedure Disconnect
&& gizli olursa daha iyi olur (protected)
    Local lcOnError
&& hata ayiklayiciyi kapatiyoruz
    lcOnError = On("ERROR")
    On Error *
    With This
        If .nhandle > 0
            SQLDisconnect(.nhandle)
        Endif
        .nhandle = 0
    Endwith
    On Error &lcOnError
    Endproc
 
&& hata gosterimi
    Procedure displayerror
 
    Local laError[1]
    =Aerror(laError)
&& hata mesajlarini alt class kodu ile gosterebilirsiniz
    _Screen.Newobject('templbl1','stb_lbltemplbl')
    _Screen.templbl1.Top = 1
    _Screen.templbl1.Caption = laError[1,2]
    _Screen.templbl1.Visible = .T.
    _Screen.Newobject('templbl2','stb_lbltemplbl')
    _Screen.templbl2.Top = _Screen.templbl1.Top + _Screen.templbl1.Height + 5
    _Screen.templbl2.Caption = "SQL Error No. " + Alltrim(Str(laError[1,5]))
    _Screen.templbl2.Visible = .T.
    Endproc
 
&& baglanti testi
    Procedure test_connection
    Local lcOnError, llError
    lcOnError = On("ERROR")
    On Error llSuccess = .F.
    This.cexecstring = "select 1"
    llSuccess = This.execute()
    On Error &lcOnError
    Return llSuccess
    Endproc
 
&& primary key haric diger alanlari updatable yapma proseduru
procedure make_updatable_cursor
Local ;
    laFields[1],;
    lcKeyField,;
    lcUpdateNameList,;
    lcUpdatableFieldList,;
    lcString, ;
    lcTableName, ;
    ln1, ;
    lnConn,;
    lnResult
 
 
lnConn = This.nhandle
lcTableName = This.ctablename
lcKeyField = This.ckeyfield
lcString = This.cexecstring
lnResult = SQLExec(lnConn, lcString, lcTableName)
 
Store [] To lcUpdateNameList, lcUpdatableFieldList
lnResult = CursorSetProp("Tables","dbo." + lcTableName, lcTableName)
lnResult =CursorSetProp("KeyFieldList", lcKeyField, lcTableName)
&& update list olusturmak icin Afields kullaniyoruz
=Afields(laFields)
For ln1 = 1 To Alen(laFields,1)
&& PK haric
    If laFields[ln1,1] == Upper(lcKeyField)
    Else
        lcUpdatableFieldList = lcUpdatableFieldList + ;
            IIF(Empty(lcUpdatableFieldList),'',',') + laFields[ln1,1]
    Endif
    lcUpdateNameList = lcUpdateNameList + ;
        IIF(Empty(lcUpdateNameList),'',',') + laFields[ln1,1] + ;
        " dbo." + lcTableName + "." + laFields[ln1,1]
Next ln1
&& ve son ayarlar
lnResult = CursorSetProp("UpdatableFieldList", lcUpdatableFieldList)
lnResult = CursorSetProp("UpdateNameList", lcUpdateNameList)
lnResult = CursorSetProp("SendUpdates", .T.)
endproc
 
 
 
    Procedure Destroy
    With This
        If .nhandle > 0
            .Disconnect()
        Endif
        If Not Empty( .nhold_displogin )
            SQLSetprop(0, 'Displogin', .nhold_displogin)
        Endif
        If Not Empty( .nhold_connecttimeout )
            SQLSetprop(0, 'ConnectTimeOut', .nhold_connecttimeout)
        Endif
    Endwith
    Endproc
 
Procedure Init
    #INCLUDE "foxpro.h"
 
    This.nhold_displogin = SQLGetprop(0, 'Displogin')
    SQLSetprop(0, 'Displogin',DB_PROMPTNEVER)
    This.nhold_connecttimeout = SQLGetprop(0, 'ConnectTimeOut')
    SQLSetprop(0, 'ConnectTimeOut', 3)
    If Empty(This.ccursor)
        This.ccursor = "T" + Sys(2015)
    Endif
    Endproc
 
Enddefine
 
&&
&& EndDefine: stb_spt_sql_connector


Visual Fox Pro
&&-- Class:        stb_lbltemplbl (d:\soykan\mysoftware\emin_elk\lib\soykan.vcx)

&&-- ParentClass:  label
&&-- BaseClass:    label
&&-- Time Stamp:   11/08/06 01:00:11 AM
&&
DEFINE CLASS stb_lbltemplbl AS label
 
 
    FontBold = .T.
    FontName = "Tahoma"
    FontSize = 18
    WordWrap = .T.
    Caption = "Label1"
    Height = 200
    Width = 500
    ForeColor = RGB(128,0,0)
    Name = "stb_lbltemplbl"
 
 
ENDDEFINE
&&
&&-- EndDefine: stb_lbltemplbl
 
 
&&bir formunuz olsun ve üzerinde bir grid var adi Grid1, classinizi forma suruklediniz biraktiniz
 
&& form init kodunuz asagidaki gibi olursa class calisacaktir
 
With This.stb_spt_sql_connector1
    .cServername=[(local)] &&serverAdi
    .cDatabasename=[Northwind] &&databaseAdi
    .cCursor=[Customers] &&cursor adi tablo adi ile ayni verildi
    .cUid=[] &&sql server kullanici adi
    .cPassword=[] &&sql server sifresi
    .cTablename=[Customers] && tabloadi
    .cKeyfield=[CustomerID] &&primary key adi
    .Connect() &&servera baglaniliyor
    &&.cExecstring = [select * from Northwind.dbo.Customers] &&SQL cumlesi
    .cExecstring = [select * from ] + .cDatabaseName + [.dbo.]+ .cTableName &&SQL cumlesi
    .execute() && ustteki SQL cumlesi calistiriliyor
    .isupdatable = .T. && olusan cursor update edilebilir isteniyorsa
    If .isupdatable = .T.
        .make_updatable_cursor()
                CursorSetProp("Buffering",5,.cTablename)
    Endif
&& sonuclar gridte gosteriliyor   
    With This.grid1
        .RecordSource = []
        .RecordSource = This.stb_spt_sql_connector1.cCursor
        .Refresh
    Endwith
Endwith
 
&& form kaydet buton kodu
If Not Tableupdate(2,.T.,Thisform.grid1.RecordSource)
    Messagebox([Kaydedilemedi],16,[kaydetme Hatasi])
Else
    Wait Window [Kaydedildi...] Nowait
    thisform.grid1.Refresh 
Endif

2

Re: SPT - SQL Pass Through ile SQL Servera baglanti class i

Soykan,
Ufak bir uyari, soyle bir goz atinca ilk hata "dbo." diye birsey eklemissin. SQL2005'te gocer bu. SQL2000'de de gocer aslinda ama onda dbo aliskanligi coktu. SQL2005'te artik schemalar cok daha fazla kullaniliyor ve dbo yerine Person, Sales vs gorme olasiligi artti.

3

Re: SPT - SQL Pass Through ile SQL Servera baglanti class i

uyari icin tesekkur ,
dbo. kullanmanin sakıncası nedir ?
kodu daha optimize olacak sekilde gerekli yerlerdeki duzeltmeleri belirtirsen cok sevinirim .
Benim acimdam cok kullanisli bir class oldu .
Ayrica bazi tablolarda  invalid column name hatasi aliyorum ama tabloyu kontrol ettigimde updatelist ve updatename list te hata gormuyorum column  adi da dogru sad

bu neden olabilir ?

4

Re: SPT - SQL Pass Through ile SQL Servera baglanti class i

Invalid column name hatasi veriyorsa field adi hatalidir. Ornegin:

select id,date from myTable

5

Re: SPT - SQL Pass Through ile SQL Servera baglanti class i

test table ım
northwind customers table i contacttitle icin hata veriyor ilginc olani herhangi bir degisiklik yaptigimda hata yok ama yeni kayit acip kaydetmek istedigim de bu hatayi aliyorum.

ayrica .dbo. kullanmanin ne sakincasi var neden ozellikle 2005 gocer ayrica 2000 dede gocuyor ?

6 Son düzenleyen, cetinbasoz (22.02.2007 11:44:21)

Re: SPT - SQL Pass Through ile SQL Servera baglanti class i

Bilmiyorum, ben yeni kayit da actim, PK hatani duzelttikden sonra.

dbo'nun derdi onun tablo adinin parcasi olmasi. SQL serverda tablo adi 3 ya da 4 parca:

Northwind.dbo.Customers

dbo yerine cetin de olabilir.

SQL 2005'te isler daha da vahim. dbo artik owner degil schema. Schemanin dbo olma sansi azaliyor. Ornegin AdventureWorks'te Employee HumanResources semasinda:

AdventureWorks.HumanResources.Employee

SQL 2000'de (ve 2005'te):

Northwind..EMployee

yazabiliyorsun. O zaman dbo ozel olarak belirtilmemis oluyor ve dbo olarak ariyor (ya da sadece Employee yazdiginda - Northwind current database ise).  VFP data explorer da bu yontemi kullandigindan 2005 tablolarinda gocuyor (HumanSources.Employee yerine Employee diye aramaya kalkiyor, oyle bir tablo yok).

7

Re: SPT - SQL Pass Through ile SQL Servera baglanti class i

anlasildi smile
PK hatam nerde imis ? ne gibi bir hata yapmisim sad

procedure make_updatable_cursor olsa olsa buradadir cunku update list ve name list burada hazirlaniyor

8

Re: SPT - SQL Pass Through ile SQL Servera baglanti class i

Northwind..customers da CustomerID nin default valuesu yok. Sen PK'yi update listesinden cikarmissin.

9

Re: SPT - SQL Pass Through ile SQL Servera baglanti class i

yaptigin duzeltme class kodlari uzerinde ise nerde oldugu belirtebilirmisin

10

Re: SPT - SQL Pass Through ile SQL Servera baglanti class i

primarykey'i cikardigin yerde

11

Re: SPT - SQL Pass Through ile SQL Servera baglanti class i

OK update listi olustururken PK kontrolu yapmayacaz anlasildi sad

12

Re: SPT - SQL Pass Through ile SQL Servera baglanti class i

Soykan,
Tam anlasilmamis:) Iletisim problemimiz var.
Ornek olarak Northwind.dbo.Customers'i kullaniyorsun. Orada CustomerID primary key ve database uretmiyor. Kullanici veriyor. Bu nedenle update listesinde olmasi gerekiyor (yeni kayitta database kendisine bu key verilmeyince NULL koyacak -eger koyabilseydi- ve primary key = NULL olunca gerisini sen dusun). Tabii Northwind'in ornek bir database olarak son derece kotu bir ornek olmasi ayri dert.

Verdigin bu firsatla buyuk harflerle kisa bir ozet (aksini savunacak yaterince guclu teziniz olmadikca gecerli):

DATABASE TARAFINDAN OLUSTURULAN VE SADECE O OLUSTURDUGUNDA GECERLI PRIMARY KEY KULLANMAYIN ( IDENTITY, AUTOINC, NEXTID METODU ILE URETILEN INTEGER KEYLER GIBI)
DIGER BIR DEYISLE uniquidentifier (guid) DISINDA PRIMARY KEY KULLANMAYIN.

OZET:
Identity ve benzeri keylerin avantaji: 0 hatta -1
GUID dezavantaji: 0 hatta +1

Tek kullanicili ortamlar disina cikma sansiniz oldugu surece boyle. Yazdiklarim garip gorunebilir ve hiz, okunabilirlik vs vs antitezler (teorikte gecerli, pratikte kanitlanamayan) var ama sayfalar surebilecek bir tartismanin 2 satirlik ozeti.

IDENTITY, AUTOINC ve turevlerine olum.

13

Re: SPT - SQL Pass Through ile SQL Servera baglanti class i

cetinbasoz yazdı:

Soykan,
Tam anlasilmamis:) Iletisim problemimiz var.
Ornek olarak Northwind.dbo.Customers'i kullaniyorsun. Orada CustomerID primary key ve database uretmiyor. Kullanici veriyor. Bu nedenle update listesinde olmasi gerekiyor (yeni kayitta database kendisine bu key verilmeyince NULL koyacak -eger koyabilseydi- ve primary key = NULL olunca gerisini sen dusun). Tabii Northwind'in ornek bir database olarak son derece kotu bir ornek olmasi ayri dert.

Verdigin bu firsatla buyuk harflerle kisa bir ozet (aksini savunacak yaterince guclu teziniz olmadikca gecerli):

DATABASE TARAFINDAN OLUSTURULAN VE SADECE O OLUSTURDUGUNDA GECERLI PRIMARY KEY KULLANMAYIN ( IDENTITY, AUTOINC, NEXTID METODU ILE URETILEN INTEGER KEYLER GIBI)
DIGER BIR DEYISLE uniquidentifier (guid) DISINDA PRIMARY KEY KULLANMAYIN.

OZET:
Identity ve benzeri keylerin avantaji: 0 hatta -1
GUID dezavantaji: 0 hatta +1

Tek kullanicili ortamlar disina cikma sansiniz oldugu surece boyle. Yazdiklarim garip gorunebilir ve hiz, okunabilirlik vs vs antitezler (teorikte gecerli, pratikte kanitlanamayan) var ama sayfalar surebilecek bir tartismanin 2 satirlik ozeti.

IDENTITY, AUTOINC ve turevlerine olum.


OK smile
buradan cikan sonuc tablolarda mutlaka PK olmali ve uniquidentifier (guid) tipinde olmali ve bunuda Database uretmeli vede asla NULL olmamali

artik northwind a guvenip ornek denemeler yapmayacagim sad dogru bildigim durumlarda bile beni yanlisa dusurdu . ayni classi northwind in baska tablosunda denedim class a hic mudahele etmedigim halde sorun cikarmadi sorunun bahsettigin PK den kaynaklandigini gorememisim sad

14

Re: SPT - SQL Pass Through ile SQL Servera baglanti class i

Ufak bir duzeltme:
"GUID olmali ve bunu da database uretmeli"

GUID olmali: OK
Database uretmeli: Database uretebilir "verilmedigi durumlar icin" - NewID(). Database daha uretmeden hatta database'e hic baglanmadan uretilebilen deger zaten. Al sana bir tane urettim:
{C8E64B94-D9C2-40B2-9DBB-CEF105517026}
Bu degeri senin X tablonda primary key olarak kullanabilirim, sende olmadigini ismdiden biliyorum:)

15

Re: SPT - SQL Pass Through ile SQL Servera baglanti class i

fox table larda GUID zaten kullaniyorum PK ler icin simdiye kadar hic basim agrimadi smile