Yorumları: 231
Konuları: 42
Kayıt Tarihi: 05-08-2019
Aktif Kullandığınız Delphi Sürümü:
Rep Puanı: 1.176 Programcı
25-12-2021, Saat: 15:06
(Son Düzenleme: 25-12-2021, Saat: 15:10, Düzenleyen: bydelphi.)
Tekrar merhaba,
10.3 de standart bileşenlerle örnek bir proje yaptım.
Kısaca anlatmak gerekirse,
2 connection var. biri kaynak diğeri hedef sunucu.ancak örnekte herikiside aynı sunucuya bağlanıyor .
açılışta bağlandığın kaynak sunucu ve veritabanına bir tablo oluşturup içerisine 5 satır veri ekliyor.
table tipli veri tipi oluşturuyor,
ve son olarak bu table tipli veri tipi ile bir prosedür yaptım , input alıyor ve sonra select ediyor.
A kaynak sunucusundaki adodatasetteki veriyi döngü ile alıp Table Value Constructor tipine çevirip üstüne ve altına gerekli ilaveleri yapıp diğer sunucun prosedürüne table tipli veri tipine gönderiyor prosedür de bu gelen tabloyu select ediyor örnekte.
oluşan kodu ve diğer çalıştırdığı tüm kodlarıda memoya aktarıyorum oradan da inceleyebilirsin oluşan kodu.
https://www.dosya.tc/server35/fmj1me/TEMP.rar.html
not:uses da globdb üniti kalmış, kaldırabilirsiniz kullanılmıyor.
görselde üstteki data tablodan direk select edilen veri,
alttaki data adodan döngü ile alınıp Table Value Constructor tipine çevirip üstüne ve altına gerekli ilaveleri yapıp diğer sunucun prosedürünün çalışmış sonucu
datadan oluşan Table Value Constructor string
İmkanın sınırı, imkansızın yanıbaşındadır. Denemeden bilemezsin.
Yorumları: 1.702
Konuları: 20
Kayıt Tarihi: 05-08-2016
Aktif Kullandığınız Delphi Sürümü:
Rep Puanı: 19.330 Üstad
@ bydelphi
Linkini verdiğiniz örnek dosya RAR ile paketlenirken yanlışlıkla şifrelemiş olabilir misiniz ?
Saygılarımla
Muharrem ARMAN
Yorumları: 231
Konuları: 42
Kayıt Tarihi: 05-08-2019
Aktif Kullandığınız Delphi Sürümü:
Rep Puanı: 1.176 Programcı
25-12-2021, Saat: 23:11
(25-12-2021, Saat: 22:41)mrmarman Adlı Kullanıcıdan Alıntı: @bydelphi
Linkini verdiğiniz örnek dosya RAR ile paketlenirken yanlışlıkla şifrelemiş olabilir misiniz ?
Çok özür
şifre 1071 yazmayı unutmuşum.
İmkanın sınırı, imkansızın yanıbaşındadır. Denemeden bilemezsin.
Yorumları: 820
Konuları: 135
Kayıt Tarihi: 07-12-2017
Aktif Kullandığınız Delphi Sürümü:
Rep Puanı: 3.030 Uzman
26-12-2021, Saat: 23:38
(Son Düzenleme: 26-12-2021, Saat: 23:49, Düzenleyen: adelphiforumz.)
@ bydelphi
Uğraşlarınız için teşekkür ederim.
Çok emek harcamışsınız elinize sağlık sağolun varolun.
Fakat örneğinizi incelediğimde parametre geçişi ben hala göremedim.
Yaptığınız örnek ExecSQL işlemi TableType sınıfında bir geçişi benmi göremedim acaba
Belkide yazdığınız kodu ben yanlış yorumlamışta olabilirim.
@ mrmarman Hocamın verdiği linkte çalışan örnek benzeri bir yapı olmuş sanırım
Değerli Üstad ve hocalarımız bu konuyu benden daha iyi değerlendireceklerdir eminim.
Bu dünyada kendine sakladığın bilgi ahirette işine yaramaz.
Yorumları: 231
Konuları: 42
Kayıt Tarihi: 05-08-2019
Aktif Kullandığınız Delphi Sürümü:
Rep Puanı: 1.176 Programcı
(26-12-2021, Saat: 23:38)adelphiforumz Adlı Kullanıcıdan Alıntı: @bydelphi
Uğraşlarınız için teşekkür ederim.
Çok emek harcamışsınız elinize sağlık sağolun varolun.
Fakat örneğinizi incelediğimde parametre geçişi ben hala göremedim.
Yaptığınız örnek ExecSQL işlemi TableType sınıfında bir geçişi benmi göremedim acaba
Belkide yazdığınız kodu ben yanlış yorumlamışta olabilirim.
@mrmarman Hocamın verdiği linkte çalışan örnek benzeri bir yapı olmuş sanırım
Değerli Üstad ve hocalarımız bu konuyu benden daha iyi değerlendireceklerdir eminim.
Aslında parametre var hemde tam senin istediğin table tipli input parametre prosedürün içerisinde ona veri gönderiyoruz.
Memo3 ü incelersen daha net görürsün. lines dan girip tüm texte bak, scrollbar kapalı tam görünmüyor .
@ VAL ın içerisinde senin milyonluk datan var datasetten while ile dönen.
alttaki kodla memo3 deki uzaksunucuda çalışacak olan procedure sqle bu parametre geçiliyor.
QrServerB.Close;
QrServerB.SQL.Text :=
StringReplace(Memo3.Text,'[@VAL]',Memo2.Text,[rfReplaceAll]);
QrServerB.Open;
İmkanın sınırı, imkansızın yanıbaşındadır. Denemeden bilemezsin.
Yorumları: 231
Konuları: 42
Kayıt Tarihi: 05-08-2019
Aktif Kullandığınız Delphi Sürümü:
Rep Puanı: 1.176 Programcı
(26-12-2021, Saat: 23:38)adelphiforumz Adlı Kullanıcıdan Alıntı: @bydelphi
Uğraşlarınız için teşekkür ederim.
Çok emek harcamışsınız elinize sağlık sağolun varolun.
Fakat örneğinizi incelediğimde parametre geçişi ben hala göremedim.
Yaptığınız örnek ExecSQL işlemi TableType sınıfında bir geçişi benmi göremedim acaba
Belkide yazdığınız kodu ben yanlış yorumlamışta olabilirim.
@mrmarman Hocamın verdiği linkte çalışan örnek benzeri bir yapı olmuş sanırım
Değerli Üstad ve hocalarımız bu konuyu benden daha iyi değerlendireceklerdir eminim.
Exec ql dediğimiz bölüme senin ihtiyacın zaten yok, sisitemi örnek için kotrol edip hazırlıyor.
test için tablo , tablo için veri , ve veriyi taşımak içinde bir adet table tipi veri tipi oluşturuyor.
bunu da zaten kotrol ederek sadece bir kere oluşturuyor hata vermemek için
yani sistemi örnek için hazırlıyoruz.
senin asıl işin butona basınca döngü ile dönüp recordseti texte dönüştürüp sonucu memoya alıp [@ val] ile prosedür table tipli değişkenine göndermek yani buton içeirisi. orayı incele
İmkanın sınırı, imkansızın yanıbaşındadır. Denemeden bilemezsin.
Yorumları: 1.702
Konuları: 20
Kayıt Tarihi: 05-08-2016
Aktif Kullandığınız Delphi Sürümü:
Rep Puanı: 19.330 Üstad
28-12-2021, Saat: 11:40
(Son Düzenleme: 28-12-2021, Saat: 11:56, Düzenleyen: mrmarman.)
Bugün izin günüm.
* Ne yapsam dedim sizin için bir test hazırladım.
* İlk defa SQLServer'a böyle bir formül ile erişim yaptım. Microsoft'a ne kadar kızsak da kaynak çok.
Sizin örnek tablo adı ile yürüdüm. Lütfen dikkatli olalım, içerisinde "DELETE FROM" içeren SQL tüm tabloyu silecektir. kayıt sayısı içerikli TEST sağlığı açısından boş tabloda çalışmak iyidir. Gerekli yedekler vs. alınarak başlayınız veya başka bir tablo üretip onunla denemelerinizi yapınız..
Aşağıdaki örnek BATCH olarak yerelde onlarca kaydı biriktirip topluca sunucuya aktarmak üzere bir örnektir.
Showmessage ile duraklamaları sizin gözle kontrol edebilmeniz için ekledim. aTestCount kadar kaydı yerelde çok hızlı bir şekilde biriktirecektir. Bunu START ve FINISH showmessage satırlarının geçiş hızı ile gözlemleyebilirsiniz.
Asıl burada test edeceğiniz unsur, iki tane "Server WAIT TEST" arasındaki süre. Bu süre BATCH içinde biriken aTestCount tane kaydın uzak sunucuya aktarım süresidir. Kanımca C# ile elde edilen süreyi yakalayacaksınız.
Eklediğim görselde 1000 record için deneme yaptım. Hem WiFi kalitemin düşüklüğü hem sanal makineden Network Bridge ile yavaşlık hem de VPN üzerinden SQLServer ağına bağlı olmam nedeniyle görece biraz yavaş kaldı ama eminim ki normal bir network'de tek tek kayıt girmekten çok çok hızlı olacaktır. Çünkü batch demek yığın demek. ADO da bunu hangi dil olursa olsun (delphi, C#, vs. ) aynı teknikle yapıyor olmalı.
Uses
DB, AdoDB, ADOInt,
ComObj, DateUtils;
const
// ------ SQL Server & Master Account ------ //
FCatalog = '<CatalogDatabase>';
FServer_Adr = '<ServerIp>';
FServer_Port = '1433';
FMaster_UserID = '<UserLogin>';
FMaster_Password = '<UserPass>';
Const
xMSSQL = 'Provider=SQLOLEDB.1;'
+'Persist Security Info=True;'
+'Data Source=%s,%s;'
+'Initial Catalog=%s;'
+'User ID=%s;'
+'Password=%s;'
+'Trusted_Connection=true;'
;
procedure TestRecords( aTestCount: Integer );
var
LConnection : OleVariant;
LRecordSet : OleVariant;
LFields : OleVariant;
LValues : OleVariant;
LRecCount : Integer;
i : Integer;
begin
LConnection := CreateOleObject('ADODB.Connection'); // veya TADOConnection.ConnectionObject
LRecordset := CreateOleObject('ADODB.RecordSet');
try
LConnection.Mode := adModeReadWrite;
LConnection.Open( Format( xMSSQL, [ FServer_Adr, FServer_Port, FCatalog, FMaster_UserID, FMaster_Password ]) );
LRecordSet.CursorLocation := adUseClientBatch; // anahtardaki "Batch" kaldırılırsa direkt kayıt yapar
LRecordSet.CursorType := adOpenDynamic;
LRecordSet.LockType := adLockBatchOptimistic; // anahtardaki "Batch" kaldırılırsa direkt kayıt yapar
//!!DİKKAT!! Empty Table...
LConnection.Execute( 'DELETE FROM [API_ERP_CariBakiyeTable]' );
LRecordset.Open( 'SELECT * FROM [API_ERP_CariBakiyeTable]', LConnection, adOpenDynamic, adLockBatchOptimistic, 0 ); // anahtardaki "Batch" kaldırılırsa direkt kayıt yapar
LRecCount := LRecordset.RecordCount;
if LRecCount > 0
then ShowmessageFmt( 'RecordCount = %d', [LRecCount] );
LFields := VarArrayOf([ 'IslemTipi', 'LogicalRef', 'Code', 'Definition',
'AlacakBakiye', 'BorcBakiye', 'SonBorcTarihi', 'SonAlacakTarihi' ]);
LValues := VarArrayOf([ 'S', 1, '1234567', 'Def Sample', 1.5, 2.5,
now(), IncDay(now(), 7) ]); // 2021-12-28 10:18:45.000
ShowMessage('Start Batch Record');
for i := 1 to aTestCount do
begin
LRecordSet.AddNew( LFields, LValues );
end;
ShowMessage('Finish Batch');
Showmessage('Server WAIT TEST: Before Update TEST Table');
LRecordSet.UpdateBatch;
showmessage('Server WAIT TEST: After Update TEST Table');
finally
LConnection.Close;
LConnection := UnAssigned;
LRecordset := UnAssigned;
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
TestRecords( 1000 );
end;
Çalışmalarınızda başarılar.
Saygılarımla
Muharrem ARMAN
Yorumları: 820
Konuları: 135
Kayıt Tarihi: 07-12-2017
Aktif Kullandığınız Delphi Sürümü:
Rep Puanı: 3.030 Uzman
@ mrmarman Hocam
Zaman ayırıp böyle bir çalışmaya katkı sağladığınız için teşekkür ederim.
Bu dünyada kendine sakladığın bilgi ahirette işine yaramaz.
Yorumları: 1.702
Konuları: 20
Kayıt Tarihi: 05-08-2016
Aktif Kullandığınız Delphi Sürümü:
Rep Puanı: 19.330 Üstad
29-12-2021, Saat: 11:37
(Son Düzenleme: 29-12-2021, Saat: 11:50, Düzenleyen: mrmarman.)
@ adelphiforumz bu arada benim için de oldukça eğitici bir soru oldu. Seni daha iyi anladım.
Hakikaten DotNet olmayan platformdan SQLServer'a olan bu yaklaşımdaki sıkıntıyı buradaki örnek ile kolları sıvayınca gördüm.
Sonradan _Recordset'i XML'ye dönüştürüp bunu StoredProc içine parametre olarak yollayıp, StoredProc yakasında XML'yi table yapıp veritabanına basınca normal çalıştı. Yani atlar ve katırlar ile yola devam edince oluyor.
Şöyle ki, denemelerimde
- Önce kendim sıfırdan ADO'nun delphi içerisinden "_Recordset" oluşturdum, oraya 1 tane kayıt girip yolladım olmadı.
- Sonra "_Recordset" olmasın OleVariant tipinde ADO'nun sistemden okuduğu şekilde "_Recordset"', OleVariant dönüştürdüm olmadı. ( dotnet de bunu yapıyor o bakımdan )
- Sonra hadi direkt OleVariant "ADODB.Recordset" oluşturup içine koydum yine olmadı.
- Son olarak sunucuya bir kaç kayıt girdim. Bunu oradan okudum, sonra gerisin geriye sunucuya geldiği gibi / olduğu gibi bastım yine kabul etmedi.
Hep aşağıdaki hata ile karşılık veri. Sanki record içeriği yer ve / veya tip uyuşmazlığı var. Onun için record tiplerini sadeleştirip (sadece iki Integer veri tipi ile) denedim ki çaprazlanmış olsun. Yine aynı hata.
Bu arada merak edenler için yazayım, recordset sağlıklı mı ? belki de @ mrmarman bunu doğru kuramadı derseniz diye, basit bir döngü ile bunu okuyup her defasında teyit ettim ve MoveToFirst ile ilk kayda döndüm - stream position (0) misali -
aşağıdaki teyit örneğinde hem LRecordSet hem de LLRecSet aynı şekilde içi dolu halde olduğu basit bir WHILE döngü ile kontrol edilebiliyor.
var
LRecordSet : OleVariant;
LLRecSet : _Recordset;
...
begin
LRecordset := CreateOleObject('ADODB.RecordSet');
LConnection := CreateOleObject('ADODB.Connection'); // veya TADOConnection.ConnectionObject
LCommand := CreateOleObject('ADODB.Command');
try
LConnection.Mode := adModeReadWrite;
LConnection.Open( Format( xMSSQL, [ FServer_Adr, FServer_Port, FCatalog, FMaster_UserID, FMaster_Password ]) );
...
...
LFields := VarArrayOf([ 'IslemTipi', 'LogicalRef', 'Code', 'Definition',
'AlacakBakiye', 'BorcBakiye', 'SonBorcTarihi', 'SonAlacakTarihi' ]);
LValues := VarArrayOf([ 'S', 1, '1234567', 'Def Sample', 1.5, 2.5, now(), IncDay(now(), 7) ]);
for i := 1 to aTestCount do
begin
LRecordSet.AddNew( LFields, LValues );
end;
...
...
if NOT LRecordSet.EOF then
begin
i := 0;
while NOT LRecordSet.EOF do
begin
Showmessage( LRecordSet.Fields[6].Value );
inc(i);
LRecordSet.MoveNext;
end;
ShowmessageFmt( 'RecordCount = %d', [ i ] );
LRecordSet.MoveFirst;
end;
LCommand.CommandType := adCmdStoredProc;
LCommand.CommandText := LProc; // 'API_ERP_CariBakiyeEkle'
LCommand.Parameters.Refresh;
//LLRecSet := IDispatch( LRecordSet ) as AdoDB._Recordset;
LCommand.Parameters[1].Value := LRecordSet;
// veya Parameters.Refresh demeden yani paramtreyi biz oluşturursak
// LCommand.Parameters.Append( LCommand.CreateParameter( '@CariBakiyeTable', adEmpty, adParamInput, 0, LRecordSet ) );
LCommand.Execute;
i := LCommand.Parameters[2];
Showmessagefmt('Rec Count = %d', [i]);
Saygılarımla
Muharrem ARMAN
|