Tüm Platformlar için Hızlı Uygulama Geliştirme Kitabı... Delphi

Konuyu Paylaş : facebook gplus twitter

Konuyu Oyla:
  • Derecelendirme: 0/5 - 0 oy
  • 1
  • 2
  • 3
  • 4
  • 5
Dataset Swap Row (Çözüldü)
#1
Selam,

DataSet üzerinde 2 satırı nasıl swap yapıyorsunuz? Yani primary key değerleri hariç olacak şekilde A satırı ile B satırının içeriğini nasıl birbiriyle yer değiştiriyorsunuz?

Ben bu durum ile master detay şeklinde çalışan ekranlarda karşılaşıyorum, yani kullanıcı bazen detaydaki bir satırı bir üstündekiyle veya bir altındakiyle yer değiştirmek isteyebiliyor 

Ben bunu daha çok SQL scriptleri ile çözüyorum ama o noktada triggerlerden kaynaklanan bazı kısıtlamalar olabiliyor, daha optimum, veritabanını yormayan daha basit bir çözümün peşindeyim, siz bu işi nasıl çözdünüz veya çözüyorsunuz? ( Trigger kısıtlamasını yokmuş gibi varsayın )
Peyami Safa: "Yaşlanarak değil, yaşayarak tecrübe kazanılır. Zaman insanları değil, armutları olgunlaştırır". 
Can Yücel: "Toprak gibi olmalısın! Ezildikçe sertleşmelisin! Seni ezenler sana muhtaç kalmalı! Hayatı sende bulmalı."
Cevapla
#2
(05-07-2017, Saat: 16:10)uparlayan Adlı Kullanıcıdan Alıntı: Linkleri Görebilmeniz İçin Giriş yap veya Üye OlSelam,

DataSet üzerinde 2 satırı nasıl swap yapıyorsunuz? Yani primary key değerleri hariç olacak şekilde A satırı ile B satırının içeriğini nasıl birbiriyle yer değiştiriyorsunuz?

Ben bu durum ile master detay şeklinde çalışan ekranlarda karşılaşıyorum, yani kullanıcı bazen detaydaki bir satırı bir üstündekiyle veya bir altındakiyle yer değiştirmek isteyebiliyor 

Ben bunu daha çok SQL scriptleri ile çözüyorum ama o noktada triggerlerden kaynaklanan bazı kısıtlamalar olabiliyor, daha optimum, veritabanını yormayan daha basit bir çözümün peşindeyim, siz bu işi nasıl çözdünüz veya çözüyorsunuz? ( Trigger kısıtlamasını yokmuş gibi varsayın )

Merhaba, Developer Express'in gridini kullanıyorsunuz sanıyorum. Bu tarz durumlar için ben ilgili DataSet içinde sanal bir RowNo oluşturuyorum, içine ilgili datayı yüklerken ardışıl bir veri atıyorum; bu alana göre gizli bir kolonu Grid'e ekleyip, o kolona göre Sort Order veriyorum. Kullanıcı bir satırı yukarı ya da aşağı taşımak istediğinde(yöntem size ait, ister drag & drop ister başka şekilde) sadece ilgili satırların RowNo alanlarını güncelliyorum.
Mal sahibi, mülk sahibi
Hani bunun ilk sahibi ?
Mal da yalan mülk de yalan
Var biraz da sen oyalan...
WWW
Cevapla
#3
(05-07-2017, Saat: 18:34)Tuğrul HELVACI Adlı Kullanıcıdan Alıntı: Linkleri Görebilmeniz İçin Giriş yap veya Üye Ol
(05-07-2017, Saat: 16:10)uparlayan Adlı Kullanıcıdan Alıntı: Linkleri Görebilmeniz İçin Giriş yap veya Üye OlSelam,

DataSet üzerinde 2 satırı nasıl swap yapıyorsunuz? Yani primary key değerleri hariç olacak şekilde A satırı ile B satırının içeriğini nasıl birbiriyle yer değiştiriyorsunuz?

Ben bu durum ile master detay şeklinde çalışan ekranlarda karşılaşıyorum, yani kullanıcı bazen detaydaki bir satırı bir üstündekiyle veya bir altındakiyle yer değiştirmek isteyebiliyor 

Ben bunu daha çok SQL scriptleri ile çözüyorum ama o noktada triggerlerden kaynaklanan bazı kısıtlamalar olabiliyor, daha optimum, veritabanını yormayan daha basit bir çözümün peşindeyim, siz bu işi nasıl çözdünüz veya çözüyorsunuz? ( Trigger kısıtlamasını yokmuş gibi varsayın )

Merhaba, Developer Express'in gridini kullanıyorsunuz sanıyorum. Bu tarz durumlar için ben ilgili DataSet içinde sanal bir RowNo oluşturuyorum, içine ilgili datayı yüklerken ardışıl bir veri atıyorum; bu alana göre gizli bir kolonu Grid'e ekleyip, o kolona göre Sort Order veriyorum. Kullanıcı bir satırı yukarı ya da aşağı taşımak istediğinde(yöntem size ait, ister drag & drop ister başka şekilde) sadece ilgili satırların RowNo alanlarını güncelliyorum.

Selam,

Mesela devreden toplam alınması gereken durumlarda bu diğer hesaplamaları etkileyebilir, fiilen iki satırı yer değiştirmemiz gereken durumlar olabiliyor,
Peyami Safa: "Yaşlanarak değil, yaşayarak tecrübe kazanılır. Zaman insanları değil, armutları olgunlaştırır". 
Can Yücel: "Toprak gibi olmalısın! Ezildikçe sertleşmelisin! Seni ezenler sana muhtaç kalmalı! Hayatı sende bulmalı."
Cevapla
#4
(05-07-2017, Saat: 18:51)uparlayan Adlı Kullanıcıdan Alıntı: Linkleri Görebilmeniz İçin Giriş yap veya Üye Ol
(05-07-2017, Saat: 18:34)Tuğrul HELVACI Adlı Kullanıcıdan Alıntı: Linkleri Görebilmeniz İçin Giriş yap veya Üye OlMerhaba, Developer Express'in gridini kullanıyorsunuz sanıyorum. Bu tarz durumlar için ben ilgili DataSet içinde sanal bir RowNo oluşturuyorum, içine ilgili datayı yüklerken ardışıl bir veri atıyorum; bu alana göre gizli bir kolonu Grid'e ekleyip, o kolona göre Sort Order veriyorum. Kullanıcı bir satırı yukarı ya da aşağı taşımak istediğinde(yöntem size ait, ister drag & drop ister başka şekilde) sadece ilgili satırların RowNo alanlarını güncelliyorum.

Selam,

Mesela devreden toplam alınması gereken durumlarda bu diğer hesaplamaları etkileyebilir, fiilen iki satırı yer değiştirmemiz gereken durumlar olabiliyor,

Evet, yürüyen bakiyede sorun olur.
Mal sahibi, mülk sahibi
Hani bunun ilk sahibi ?
Mal da yalan mülk de yalan
Var biraz da sen oyalan...
WWW
Cevapla
#5
Bi ara şöyle bişi yapmıştım;
Ürün ağacı tablosunda alttaki kaydı üste al, üstteki kaydı aşağı çek gibi şeyler istemişlerdi, bunlarda tabi tabloda kalıcı olmalıydı. Tabloya SIRA (Int) olarak bi alan eklemiştim, order by ile bu alana göre sıralama yapıyodum. Her yeni kayıt girişinde SIRA+1 yapıp yeni kaydı atıyodum dolayısı ile 1,2,3,.... şeklinde kayıtlarım oluyodu. Kullanıcı grid de herhangi bir kayda sağ klik yaptığında Üste al- Alta al şeklinde popup tan hangisini seçtiyse ona göre bulunan kaydın ve sonraki yada önceki kaydın id lerini SIRALA(Tasinacak_Id,Yerine_Id) isminde Stored Proc. a 2 parametre olarak gönderiyodum Stored Proc. tada SIRA alanı değerlerini birbirlerinin yerine değiştirip, yazıp, Query Close-Open yapıyodum.
Linkleri Görebilmeniz İçin Giriş yap veya Üye Ol
WWW
Cevapla
#6
Bu sorun ile ilgili şöyle bir şey geliştirdim, bunu nasıl daha efektif yapabiliriz?

interface

uses
    Data.DB;                         //  TBookmarks, TDataSet

type
  TStringArray = array of string;
  TStringArrayHelper = record helper for TStringArray
    public
      function Count: Integer;
  end;
  TDataSetHelper = class helper for TDataSet
    public
    // ...
    // ...
    // ...
     procedure SwapRow(Yukari: Boolean; const Dokunulmazlar: TStringArray);
  end;

implementation

uses
    System.SysUtils //  Format
  , System.Variants //  null
  ;

{ TStringArrayHelper }

function TStringArrayHelper.Count: Integer;
var
  I: integer;
begin
  Result := 0;
  for I := Low(Self) to High(Self) do Inc(Result);
end;

{ TDataSetHelper }

procedure TDataSetHelper.SwapRow(Yukari: Boolean; const Dokunulmazlar: TStringArray);
var
 aUstSatir, aAltSatir: Variant;
 X: Integer;
 procedure Swapla(aKaynak: Variant);//(const Dokunulmazlar: TStringArray);
 var
   I, J: Integer;
   Atla: Boolean;
 begin
   Edit;
   for I := 0 to FieldCount - 1 do
       if (Fields[I].CanModify = TRUE) then begin
           Atla := False;
           for J := low(Dokunulmazlar) to high(Dokunulmazlar) do
               if (Fields[I].FieldName = Dokunulmazlar[J]) then begin
                   Atla := TRUE;
                   Break;
               end;
           if NOT Atla then Fields[I].Value := aKaynak[I];
       end;
   Post;
 end;
begin
 if State in dsEditModes then Post; // Bu noktada hata verirse kontrol etmiyoruz, zira bu metodun çağırıldığı yerde zaten kontrol edilmeli...

 aUstSatir := VarArrayCreate([0, FieldCount - 1], VarVariant);
 aAltSatir := VarArrayCreate([0, FieldCount - 1], VarVariant);

 // Yukarı gideceksek önceki satıra, aşağı gideceksek sonraki satıra gidiyoruz
 if Yukari then Prior else Next; for X := 0 to FieldCount - 1 do aUstSatir[X] := Fields[X].Value; // Üstte kalacak satırı okuyoruz

 // Diğer satıra geçiyoruz
 if Yukari then Next else Prior; for X := 0 to FieldCount - 1 do aAltSatir[X] := Fields[X].Value; // Altta kalacak satırı okuyoruz

 Swapla(aUstSatir);

 if Yukari then Prior else Next; // ilk okuduğumuz satıra geri gidiyoruz

 Swapla(aAltSatir);
end;

Örnek kullanımı da şu şekilde olur,

  if (Sender = Button_Yukari) then AltTablo.SwapRow( TRUE, ['ID'] ) else
  if (Sender = Button_Asagi)  then AltTablo.SwapRow( FALSE,['ID'] );
Peyami Safa: "Yaşlanarak değil, yaşayarak tecrübe kazanılır. Zaman insanları değil, armutları olgunlaştırır". 
Can Yücel: "Toprak gibi olmalısın! Ezildikçe sertleşmelisin! Seni ezenler sana muhtaç kalmalı! Hayatı sende bulmalı."
Cevapla
#7
Uğur bey, bu şekilde bir kullanım tehlikeli olur kanaatimce. Çünkü, örneğinizden gözlemlediğim kadarı ile; ID alanı hariç field'ların yerlerini değiştiriyorsunuz. Daha açık ifade etmek gerekir ise, veritabanından ham datayı çektiğiniz de ID'si 17 olan ve Adi alanı ABC olan kayıtta artık ID'si 18 olan ve CDE olan kayıttaki alanlar bulunacak, ancak ID'ler sabit kalacak. Bu durum, aynı dataset üzerinden veritabanını güncellemek istediğinizde istemediğiniz karmaşalara neden olabilir.

Veri tabanından datanın ilk çekildiği an
-----------------------------------------------
ID      Adi
-------------
17      ABC
18      DEF

Alttaki satır üstteki satıra kopyalandığı an
--------------------------------------------------
ID      Adi
-------------
17     DEF
18     ABC

Kayıtların fiziksel sıralamasını illa'da TDataSet üzerinden değiştirmeyi istiyor iseniz, size TDataSet'in private metodu olan MoveBuffer metodunu önerebilirim.

Ancak değişik çözümler sunmak adına, datayı ilgili RDBMS'den çeker iken belki bir RowNumber sanal alanı ile çekebilirsiniz.(SQL Server için ROW_NUMBER fonksiyonu kullanılabilir) Ya da bu işi Grid üzerinde de halledebilirsiniz. Karar sizin.
Mal sahibi, mülk sahibi
Hani bunun ilk sahibi ?
Mal da yalan mülk de yalan
Var biraz da sen oyalan...
WWW
Cevapla
#8
(06-07-2017, Saat: 18:33)Tuğrul HELVACI Adlı Kullanıcıdan Alıntı: Linkleri Görebilmeniz İçin Giriş yap veya Üye OlUğur bey, bu şekilde bir kullanım tehlikeli olur kanaatimce. Çünkü, örneğinizden gözlemlediğim kadarı ile; ID alanı hariç field'ların yerlerini değiştiriyorsunuz. Daha açık ifade etmek gerekir ise, veritabanından ham datayı çektiğiniz de ID'si 17 olan ve Adi alanı ABC olan kayıtta artık ID'si 18 olan ve CDE olan kayıttaki alanlar bulunacak, ancak ID'ler sabit kalacak. Bu durum, aynı dataset üzerinden veritabanını güncellemek istediğinizde istemediğiniz karmaşalara neden olabilir.

Veri tabanından datanın ilk çekildiği an
-----------------------------------------------
ID      Adi
-------------
17      ABC
18      DEF

Alttaki satır üstteki satıra kopyalandığı an
--------------------------------------------------
ID      Adi
-------------
17     DEF
18     ABC

Kayıtların fiziksel sıralamasını illa'da TDataSet üzerinden değiştirmeyi istiyor iseniz, size TDataSet'in private metodu olan MoveBuffer metodunu önerebilirim.

Ancak değişik çözümler sunmak adına, datayı ilgili RDBMS'den çeker iken belki bir RowNumber sanal alanı ile çekebilirsiniz.(SQL Server için ROW_NUMBER fonksiyonu kullanılabilir) Ya da bu işi Grid üzerinde de halledebilirsiniz. Karar sizin.

Tuğrul Bey, doğru, bu tarz bir kullanım veritabanında özellikle ID ile ID'nin temsil ettiği verilerin sıkı sıkıya birbirine bağlı olmasının istendiği durumlar için kullanılmamalıdır. Seçimlik parametrelerin olduğu tablolar buna örnek verilebilir, zaten kimse böyle bir şey istemez.

Bununla birlikte bu yöntem, veritabanında Unique Index içeren alanların olması halinde de duplicate key hatası verecektir.

Fakat, hem sizin, hem de benim belirttiğim şerhler dışında bence yöntemin kullanılmaması için bir sakınca göremiyorum.

XE 10.2 Tokyo ile denemelerimi yaptığım için Class Helper'lere Berlin sürümünden itibaren bazı erişim kısıtlamaları getirildi, yani ana sınıfın private bölümündeki alanlara artık erişim kaldırıldı, dolayısıyla bahsettiğiniz TDataSet.MoveBuffer metodu da private kısmında olduğundan, Class Helper aracılığıyla erişilemiyor. (Class Helper olması şart değil) Sizden bu noktada bir kod örneği alabilir miyiz?

İlgili değişiklik: Linkleri Görebilmeniz İçin Giriş yap veya Üye Ol
Peyami Safa: "Yaşlanarak değil, yaşayarak tecrübe kazanılır. Zaman insanları değil, armutları olgunlaştırır". 
Can Yücel: "Toprak gibi olmalısın! Ezildikçe sertleşmelisin! Seni ezenler sana muhtaç kalmalı! Hayatı sende bulmalı."
Cevapla
#9
Merhaba, ben Delphi Seattle kullanıyorum. Dolayısı ile private üyelere erişim iznim mevcut. Private erişimi kapatmaları iyi olmamış. Ama her zaman başka çözümler vardır. Tabii efektif midir tartışılabilir. Sizin için şöyle küçük bir örnek hazırladım:

  TDataSetHelper = class helper for TDataSet
  public
    procedure UpDown(CurIndex, NewIndex: Integer);
  end;

{ TDataSetHelper }

procedure TDataSetHelper.UpDown(CurIndex, NewIndex: Integer);
type
  TMoveBufferProc = procedure(ACurIndex, ANewIndex: Integer) of object;
var
  P : TMoveBufferProc;
begin
  TMethod(P).Code := @TDataSet.MoveBuffer;
  TMethod(P).Data := Self;

  P(CurIndex, NewIndex);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  dxMemData1.UpDown(1, 2); // dxMemData1 TdxMemData türündedir.
end;

Yada RTTI ile de erişilebilir, tabii onu da kısıtlamadılar ise. Hiç birisi olmuyor ise, o zaman DB.pas proje klasörüne kopyalanır ve gönül rahatlığı ile kullanılır. (Tabii sadece onu kopyalamak yetmeyebilir, "compiled with differen unit" hatası verirse diğer unitleri de kopyalamak icap eder.)
Mal sahibi, mülk sahibi
Hani bunun ilk sahibi ?
Mal da yalan mülk de yalan
Var biraz da sen oyalan...
WWW
Cevapla
#10
(07-07-2017, Saat: 13:49)Tuğrul HELVACI Adlı Kullanıcıdan Alıntı: Linkleri Görebilmeniz İçin Giriş yap veya Üye OlMerhaba, ben Delphi Seattle kullanıyorum. Dolayısı ile private üyelere erişim iznim mevcut. Private erişimi kapatmaları iyi olmamış. Ama her zaman başka çözümler vardır. Tabii efektif midir tartışılabilir. Sizin için şöyle küçük bir örnek hazırladım:

  TDataSetHelper = class helper for TDataSet
  public
    procedure UpDown(CurIndex, NewIndex: Integer);
  end;

{ TDataSetHelper }

procedure TDataSetHelper.UpDown(CurIndex, NewIndex: Integer);
type
  TMoveBufferProc = procedure(ACurIndex, ANewIndex: Integer) of object;
var
  P : TMoveBufferProc;
begin
  TMethod(P).Code := @TDataSet.MoveBuffer;
  TMethod(P).Data := Self;

  P(CurIndex, NewIndex);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  dxMemData1.UpDown(1, 2); // dxMemData1 TdxMemData türündedir.
end;

Yada RTTI ile de erişilebilir, tabii onu da kısıtlamadılar ise. Hiç birisi olmuyor ise, o zaman DB.pas proje klasörüne kopyalanır ve gönül rahatlığı ile kullanılır. (Tabii sadece onu kopyalamak yetmeyebilir, "compiled with differen unit" hatası verirse diğer unitleri de kopyalamak icap eder.)

TUNIQuery nesnesiyle kodu denediğimde herhangi bir tepki vermedi, denememi XE7'de yaptım.
Cevapla

Konuyu Paylaş : facebook gplus twitter



Konu ile Alakalı Benzer Konular
Konular Yazar Yorumlar Okunma Son Yorum
  [Çözüldü] Otomatik artan alan değerlerini sıfırlama Lord_Ares 4 109 17-10-2018, Saat: 08:54
Son Yorum: esistem
  [ÇÖZÜLDÜ] Query ismini değişken olarak göndermek Lord_Ares 14 294 12-10-2018, Saat: 12:33
Son Yorum: Lord_Ares
  [Çözüldü] SQL insert ederken autoincrement alan Lord_Ares 10 204 06-10-2018, Saat: 21:08
Son Yorum: Lord_Ares
  CxGrid'de Runtime Filtreleme (Çözüldü) yhackup 1 90 03-10-2018, Saat: 17:04
Son Yorum: adelphiforumz
  [ ÇÖZÜLDÜ ] RAD Studio Community Edition ? Mr.Developer 3 217 11-09-2018, Saat: 10:20
Son Yorum: Mr.Developer



Konuyu Okuyanlar: 1 Ziyaretçi