Ugur cok guzel anlatmis, ufak bir ekleme (kafa karisikligina karsi). SQL sorgusunu daha o parameterler yokken yazabilir ve hatta baska bir fonksiyona gonderebilirsin (o sirada duz string, daha icindeki parametreler aranmiyor). Istedigin zaman parametreyi tanimlar, degerini verirsin ve sorguyu kullanabilirsin, Sonra parametre degerini degisitirip gene sorguyu kullanabilirsin. Ornegin (ornegin uzun gorundugune bakma ornek verirken birden fazla seye ornek olsun diye jenerik cursoradapter class var icinde. O class bir kere yazilip kenarda kullanima hazir duran sey. Asil kod bastaki birkac satir. SQL serverdan Customers datasi verilen ulkeye gore alinip edit ediliyor. Dikkat et tanim once, kullanim sonra 'USA' ve 'UK' ile iki kez):
Visual Fox Pro
Local loCursor, lcConStr
lcConStr = 'Provider=SQLNCLI;Trusted_connection=Yes;Server=.\SQLExpress'
loCursor = Createobject('CaGeneric',m.lcConStr)
With loCursor
.Alias = 'myTable'
TEXT TO .SelectCmd noshow
SELECT * FROM NorthWind..Customers cus WHERE country = ?m.Country
ENDTEXT
Endwith
Country = 'USA'
If loCursor.QueryFill()
Select (loCursor.Alias)
loCursor.MakeUpdatable('NorthWind..Customers','customerId')
Browse Last
Tableupdate(2,.T.,loCursor.Alias)
Endif
Country = 'UK'
If loCursor.QueryFill()
Select (loCursor.Alias)
loCursor.MakeUpdatable('NorthWind..Customers','customerId')
Browse Last
Tableupdate(2,.T.,loCursor.Alias)
Endif
Define Class CaGeneric As CursorAdapter
CompareMemo = .F.
FetchAsNeeded = .T.
FetchSize = 100
FetchMemo = .T.
BatchUpdateCount = 100
WhereType = 1
AllowSimultaneousFetch = .T.
MapVarchar = .T.
MapBinary = .T.
BufferModeOverride = 5
DataSourceType = 'ADO'
InsertCmdDataSourceType = 'ADO'
UpdateCmdDataSourceType = 'ADO'
DeleteCmdDataSourceType = 'ADO'
Procedure Init(tcConnectionString)
Set Multilocks On
Local loConnDataSource
loConnDataSource = Createobject('ADODB.Connection')
loConnDataSource.ConnectionString = m.tcConnectionString
loConnDataSource.Open()
This.Datasource = Createobject('ADODB.RecordSet')
This.Datasource.CursorLocation = 3 && adUseClient
This.Datasource.LockType = 3 && adLockOptimistic
This.Datasource.ActiveConnection = m.loConnDataSource
loCommand = Createobject('ADODB.Command')
loCommand.ActiveConnection = loConnDataSource
This.AddProperty('oCommand',loCommand)
Store loCommand To ;
This.UpdateCmdDataSource,;
This.InsertCmdDataSource,;
This.DeleteCmdDataSource
Endproc
Procedure MakeUpdatable(tcTableName,tckeyField,tlDoNotIncludeKey)
This.Tables = m.tcTableName
This.KeyFieldList = m.tckeyField
Local ix, lnUpdateableFCount
lnUpdateableFCount = Fcount(This.Alias)-Iif(This.DataSourceType='ADO',1,0) && last one is ADOBOOKMARK
For ix = 1 To m.lnUpdateableFCount
If !m.tlDoNotIncludeKey Or !(Upper(Field(m.ix,This.Alias,0)) == Upper(m.tckeyField))
This.UpdatableFieldList = This.UpdatableFieldList + ;
IIF(Empty(This.UpdatableFieldList),'',',') + ;
FIELD(m.ix,This.Alias,0)
Endif
This.UpdateNameList = This.UpdateNameList + ;
IIF(Empty(This.UpdateNameList),'',',') + ;
TEXTMERGE('<<FIELD(m.ix,this.Alias,0)>> <<m.tcTableName>>.<<FIELD(m.ix,this.Alias,0)>>')
Endfor
Endproc
Procedure QueryFill()
Local llSuccess
If This.DataSourceType ="ADO"
llSuccess = This.CursorFill(.F.,.F.,0,This.oCommand)
Else
llSuccess = This.CursorFill(.F.)
Endif
If !m.llSuccess
If This.DataSourceType ="ADO"
lcMessage = This.oCommand.CommandText + Chr(13) + This.GetErrorExplanation()
Else
lcMessage = This.GetErrorExplanation()
Endif
Messagebox(m.lcMessage)
Endif
Return m.llSuccess
Endproc
Procedure GetErrorExplanation
Local lcError,ix
Local Array aWhy[1]
Aerror(aWhy)
lcError = ""
For ix = 1 To 7
lcError = m.lcError + Transform(aWhy[m.ix]) + Chr(13)
Endfor
Return m.lcError
Endproc
Enddefine
Parametre faydali birsey olmaktan ote olmazsa olmaz birsey. Esneklik saglamasinin ve degiskenleri saglamasinin yaninda:
-Dogru yazmani saglar (ornegin SQL server'da [Ali'nin Sirketi] yazmak istiyorsan parametre ile oyle yazarsin, parametre kullanmazsan [Ali''nin Sirketi] yazman gerekir. Ya da tarih yazamak istediginde belli standard formatlardan biriyle string olarak yazmakla ugrasmazsin, dogrudan tarih yaz sen parametre olarak gitsin, nasil verilecekse driverlar cevirir):
Visual Fox Pro
lcSQL = "insert into myTable (kayitID, gelisZamani, aciklama, resim) values (?m.ID, ?m.TarihSaat, ?m.detaylar, ?m.resim)"
ID = 1
TarihSaat = datetime()
Detaylar = "Bir varmis bir yokmus, Ahmet'in vs vs ve hatta bir dosyadan tonlarca ek:" + FileToStr("c:\Temp\Detay.txt")
Resim = CreateBinary(FileToStr("c:\temp\BirResim.jpg"))
SQLExec(m.lnHandle, m.lcSQL)
-AMA EN ONEMLISI database'ine sizilmasini onler. Bu sizma 'SQL injection attack' olarak meshur ve en onemli ve veri tabani programcilarinin en ciddi 10 hatasi arasinda yer aliyor. Asla ve asla:
Visual Fox Pro
lcSQL = "select * from tabloadi where a = '" + m.a + "' and c = " + m.c
gibi bir SQL kullanma. Bunu yaparsan bir hacker sana minnettarligini yakinda sunacaktir. O sunmasa da boyle SQL yazdigini gorunce sana is vermezler, tek soruda cakarsin (hos gerci bu sekilde kullandigi halde su anda SQL DBA olani da taniyorum).