Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Problem z TcxGrid - blad po usunieciu ostatniego rekordu

50 views
Skip to first unread message

jh

unread,
Feb 27, 2012, 12:19:08 PM2/27/12
to
TcxGrid - 11.2.3
Delphi XE2 Pro Upd3
W7 Pro 64 Bit
FB 2.5
AnyDAC - 5.0.5.2073

Problem powtarzalny - również na nowym, gołym projekcie. Pewnie coś źle
ustawiam :(

Dwa datasety TADQuery, do niezbędnego minimum na FB:

TABLE TABLEM (
MID INTEGER NOT NULL,
MVALUE VARCHAR(10)
);

TABLE TABLED (
DID INTEGER NOT NULL,
MID INTEGER NOT NULL,
DVALUE VARCHAR(10)
);

ALTER TABLE TABLED ADD CONSTRAINT FK_TABLED_1 FOREIGN KEY (MID)
REFERENCES TABLEM (MID) ON DELETE CASCADE ON UPDATE CASCADE;

SQL
select * from TableM
select * from TableD where MID = :MID

Między datasetami ustawione relacje master-detail.

W TcxGrid dwa widoki:
lvTableM: TcxGridLevel;
tvTableM: TcxGridDBTableView;
lvTableD: TcxGridLevel;
tvTableD: TcxGridDBTableView;


DataController dla mastera:
DetailInSQLMode = True
GridMode = False
SmartRefresh = False
SyncMode = True

KeyFieldNames = MID

DataController dla detali:
DetailInSQLMode = False
GridMode = False
SmartRefresh = False
SyncMode = True
DetailKeyFieldNames = MID
KeyFieldNames = DID
MasterKeyFieldNames = MID

reszta domyślnie.

Dopóki po usunięciu danych z mastera został choć jeden rekord - nic się
nie dzieje. Po usunięciu ostatniego rekordu z mastera dostaję wyjątek.

First chance exception at $76CAB9BC. Exception class EListError with
message 'List index out of bounds (0)'. Process FBData.exe (3452)

function TcxDataStorage.GetDisplayText(ARecordIndex: Integer; AValueDef:
TcxValueDef): string;
var
P: PAnsiChar;
begin
Result := '';
P := RecordBuffers[ARecordIndex]; // <----- EXCEPTION
if (P <> nil) and CheckValueDef(ARecordIndex, AValueDef) then
Result := AValueDef.GetDisplayText(P);
end

Call stack:

:76cab9bc KERNELBASE.RaiseException + 0x58
:00451afa TList.Get + $1A
:00451afa TList.Get + $1A
cxDataStorage.TcxDataStorage.GetValue(0,$4C7B510)
cxCustomData.TcxCustomDataController.GetStoredValue(0,$402D9C0)
cxCustomData.TcxCustomDataController.GetInternalValue(0,$402D9C0)
cxCustomData.TcxCustomDataRelationList.GetValueAsDetailObject(0)
cxCustomData.TcxCustomDataRelationList.GetDetailObject(0)
cxCustomData.TcxCustomDataController.GetDetailExpanding(0)
cxCustomData.TcxCustomDataController.ChangeDetailExpanding(0,True)
cxDBData.ExpandDetails($3F593C0,0,Null)
cxDBData.TcxDBDataController.SyncMasterDetail
cxDBData.TcxDBDataController.SyncMasterDetailDataSetPos
cxDBData.TcxDBDataController.SyncDataSetPos
cxDBData.TcxDBDataController.UpdateFocused
cxCustomData.CheckAfterLoad
cxCustomData.TcxCustomDataController.LoadStorage
cxDBData.TcxDBDataController.LoadStorage
cxCustomData.TcxCustomDataController.UpdateStorage(False)
cxCustomData.TcxCustomDataController.DataChanged(dcTotal,-1,-1)
cxCustomData.TcxCustomDataProvider.DataChanged(dcTotal,-1,-1)
cxDBData.TcxDBDataLink.DataSetChanged

Gdzie popełniam błąd?

jh

jh

unread,
Feb 28, 2012, 10:38:02 AM2/28/12
to
Support DevExa wolałby nie instalować AnyDACa, żeby to sprawdzić. Czy
mógłby ktoś zrobić podobny projekt i sprawdzić, czy jest to powtarzalna
sytuacja?

jh

R.e.m.e.K

unread,
Feb 28, 2012, 11:34:00 AM2/28/12
to
Jesli chcesz zeby ktos to sprawdzil to moze wrzuc taki prosty projekt gdzies
na www i daj linka.

--
pozdro
R.e.m.e.K

jh

unread,
Feb 28, 2012, 11:48:09 AM2/28/12
to
W dniu 28.02.2012 17:34, R.e.m.e.K pisze:
OK, aczkolwiek chodzi mi o to, że może ja popełniam jakąś gafę w
konfiguracji. Zrobiłem od zera banalny projekt z dwoma tabelkami i mam
to samo. Ale ok, naszykuję pliczek bazy (Firebird) i projekt.

jh


jh

unread,
Feb 28, 2012, 3:58:59 PM2/28/12
to
http://jh.net.pl/tmp/grid.zip
10 MB

W środku jest projekt Win32 w Delphi XE2 oraz wersja skompilowana,
potrzebny jest AnyDAC i TcxGrid. W katalogu aplikacji (/Win32/Debug/)
jest plik bazy TCXERROR.FDB, oraz biblioteka Firebird Embedded - więc
nie trzeba instalować serwera. W memo jest info, co i jak - można
ręcznie, albo kliknąć w to memo i samo się zepsuje ;)

jh

arturs

unread,
Feb 28, 2012, 5:56:02 PM2/28/12
to
W dniu 2012-02-28 21:58, jh pisze:
na skompilowanym jest tak jak opisujesz...
reszty nie mam więc nie pomogę..
że tak zapytam - taki panel na górze z konstruktorem filtra to
TCxNavigator z funkcją wbudowaną czy jakiś Twój patent?

jh

unread,
Feb 28, 2012, 6:00:07 PM2/28/12
to
W dniu 28.02.2012 23:56, arturs pisze:
> że tak zapytam - taki panel na górze z konstruktorem filtra to
> TCxNavigator z funkcją wbudowaną czy jakiś Twój patent?

Nie, to jest od DevEx razem z gridem.

jh

arturs

unread,
Feb 28, 2012, 6:22:54 PM2/28/12
to
W dniu 2012-02-29 00:00, jh pisze:
to to:
http://devexpress.com/Products/VCL/ExQuantumGrid/info.xml
?

jh

unread,
Feb 28, 2012, 6:28:43 PM2/28/12
to
W dniu 29.02.2012 00:22, arturs pisze:
> http://devexpress.com/Products/VCL/ExQuantumGrid/info.xml
> ?

Tak.

jh

R.e.m.e.K

unread,
Feb 28, 2012, 6:34:01 PM2/28/12
to
Dnia Mon, 27 Feb 2012 18:19:08 +0100, jh napisał(a):

> function TcxDataStorage.GetDisplayText(ARecordIndex: Integer; AValueDef:
> TcxValueDef): string;
> var
> P: PAnsiChar;
> begin
> Result := '';
> P := RecordBuffers[ARecordIndex]; // <----- EXCEPTION
> if (P <> nil) and CheckValueDef(ARecordIndex, AValueDef) then
> Result := AValueDef.GetDisplayText(P);
> end

W XE tez sie sypie, ale tu:

function TcxDataStorage.GetRecordBuffer(Index: Integer): PAnsiChar;
begin
if Index >= 0 then
Result := PAnsiChar(FRecordBuffers[Index]) <--------------
else
Result := PAnsiChar(FInternalRecordBuffers[-Index - 1]);
end;

Najnowszy DevEx sprzed 2 czy 3 dni.

--
pozdro
R.e.m.e.K

jh

unread,
Feb 28, 2012, 7:09:00 PM2/28/12
to
W dniu 29.02.2012 00:34, R.e.m.e.K pisze:
> W XE tez sie sypie, ale tu:
>
> function TcxDataStorage.GetRecordBuffer(Index: Integer): PAnsiChar;
> begin
> if Index>= 0 then
> Result := PAnsiChar(FRecordBuffers[Index])<--------------
> else
> Result := PAnsiChar(FInternalRecordBuffers[-Index - 1]);
> end;
>
> Najnowszy DevEx sprzed 2 czy 3 dni.

Wiem tyle, że to problem na styku DevEx i AnyDAC, bo ten grid, ale z
komponentami Interbase działa poprawnie - ta sama konfiguracja. I
odwrotnie - AnyDAC z dwoma gridami TDBGrid działa poprawnie. Bardziej
skłaniam się ku temu, że jednak większa wina jest po stronie grida, bo
wystarczy wyłączyć level detali i działa. Jakieś podobne jaja mam z
ichnim widokiem DB Layout, który się wykrzacza na równie banalnym
projekcie master-detail. Ustawiam ten że DB Layout jako detail. Przy
przejściu do kolejnego wiersza master przy rozwiniętym podglądzie detali
mam od razu AV. Może ja coś źle tu robię, ale zastąpienie tego typu
widoku innym takiego błędu nie generuje.

jh

R.e.m.e.K

unread,
Feb 28, 2012, 7:14:38 PM2/28/12
to
Dnia Wed, 29 Feb 2012 01:09:00 +0100, jh napisał(a):

> Wiem tyle, że to problem na styku DevEx i AnyDAC, bo ten grid, ale z
> komponentami Interbase działa poprawnie - ta sama konfiguracja. I
> odwrotnie - AnyDAC z dwoma gridami TDBGrid działa poprawnie. Bardziej

Sprobuj moze poprosic o pomoc autora AnyDACa, to mam wrazenie zyczliwy
czlowiek, no i tytan pracy :-) moze akurat ma DevExa i wykaze jasno ich
wine, wtedy DevEx bedzie musial konkretnie zareagowac. Moze tez zapodaj ten
projekt na forum DevExa, zeby inni userzy potestowali.
Sam nie uzywalem jeszcze devexowego grida w takim ukladzie jaki tam masz,
wiec nie spotkalem problemu, ale inni pewnie tak.

--
pozdro
R.e.m.e.K

jh

unread,
Feb 28, 2012, 7:16:23 PM2/28/12
to
W dniu 29.02.2012 01:14, R.e.m.e.K pisze:
> Sprobuj moze poprosic o pomoc autora AnyDACa

Zrobiłem to już jakieś 2 godziny temu ;) Czekam na odpowiedź.

jh

jh

unread,
Mar 2, 2012, 2:53:52 AM3/2/12
to
W dniu 27.02.2012 18:19, jh pisze:

> Dopóki po usunięciu danych z mastera został choć jeden rekord - nic się
> nie dzieje. Po usunięciu ostatniego rekordu z mastera dostaję wyjątek.

Mam prośbę - gdyby komuś się chciało - niech zrobi taki mini projekt z
dwoma TADQuery (select from master, select from detail where
masterid=:masterid, ustawiony MasterSource i pole w detail), TcxGrid -
dwa levele, w każdym DB Table jako view, w układzie master-detail
(Detail in SQL Mode = true, grid mode = false) i niech sprawdzi, czy
jemu też się to dzieje - czyli błąd po usunięciu ostatniego rekordu w
masterze. Support DevExpress umył rączki - skoro z innymi komponentami
niż AnyDAC działa, to znaczy, że nie ich wina, choć błąd występuje w
metodzie ich komponentów. AnyDAC w ogóle nie odpisuje od tych kilku dni,
a podejrzewam, że odpowiedź będzie podobna - skoro AnyDAC w takim
układzie z innymi gridami działa poprawnie, to znaczy, że nie ich
wina... Oddałem projekt, a tu klient zgłasza taki zonk i nie mam jak to
załatać :(

jh

Arivald

unread,
Mar 2, 2012, 5:57:39 AM3/2/12
to
W dniu 2012-03-02 08:53, jh pisze:
To jest ich wina, imho. Komponenty powinny to robić w bezpieczny sposób,
a sprawdzenie Count'a nie kosztowało by za wiele. A najprawdopodobniej
błąd jest w TcxDBDataController.SyncMasterDetail(), które próbuje
synchronizacja z pustym datasetem, próbuje wyciągnąć wartość
nieistniejącego pola.

Jak masz źródła, to spróbuj poprawić. Albo pokaż je na grupie, zobaczymy
gdzie jest błąd. Będziesz mógł im wysłać poprawkę, i moze uda się
zreplikować błąd na wbudowanym datasecie.


A jeśli nie będą chcieli poprawić, i masz źródła, to można spróbować
hakowania run-time, i po prostu zamienić ich implementację na inną,
działającą. Zadziała to z funkcją publiczną lub chonioną, lub każdą inną
jeśli jesteś w stanie znaleźć jej adres run-time (np RTTI).

--
Arivald

arturs

unread,
Mar 2, 2012, 7:46:58 AM3/2/12
to
A czy ten problem pojawia się tylko z firebirdem czy też np. z MSSQL'em?
Bo w sumie to chyba dosyć typowa sytuacja że coś usuwasz w master/detail
a nie jakieś warunki szczególne..

jh

unread,
Mar 3, 2012, 8:30:07 AM3/3/12
to
W dniu 02.03.2012 11:57, Arivald pisze:
> To jest ich wina, imho. Komponenty powinny to robić w bezpieczny sposób,
> a sprawdzenie Count'a nie kosztowało by za wiele. A najprawdopodobniej
> błąd jest w TcxDBDataController.SyncMasterDetail(), które próbuje
> synchronizacja z pustym datasetem, próbuje wyciągnąć wartość
> nieistniejącego pola.
>
> Jak masz źródła, to spróbuj poprawić. Albo pokaż je na grupie, zobaczymy
> gdzie jest błąd. Będziesz mógł im wysłać poprawkę, i moze uda się
> zreplikować błąd na wbudowanym datasecie.
>
>
> A jeśli nie będą chcieli poprawić, i masz źródła, to można spróbować
> hakowania run-time, i po prostu zamienić ich implementację na inną,
> działającą. Zadziała to z funkcją publiczną lub chonioną, lub każdą inną
> jeśli jesteś w stanie znaleźć jej adres run-time (np RTTI).

Wina jest ewidentnie w DevExpress. Kontroler ma dwa bufory, jeden
odwołuje się do wewnętrznego bufora i w nim występuje błąd. Dzieje się
tak, że mając dwie TList sprawdzają, czy Index rekordu w jednej jest >=
0, a w drugiej już nie. Przy czym, w niektórych wywołaniach jeżeli lista
jest pusta tworzony jest wewnętrzny bufor - ta lista druga, a w innych
nie. Ciężko to debuggować, bo wejście do metody przy tylko jednej
kolumnie i jednym rekordzie ma miejsce np. 45 razy i prowadzi z różnych
miejsc. Już mi się po prostu nie chce. Zrobiłem protezę - czyli w
datasecie master w BeforeDelete zamykam detale, jeżeli liczba rekordów
master = 1, a otwieram w after post/cancel, o ile liczba rekordów jest >
0. Wiem, że brzydkie, ale to załatwia też drugi bug, który pojawia się
wtedy, kiedy wstawiam rekord do mastera i jeszcze nie jest zakomitowany,
a chcę wstawić rekord do detali i rozwijam widok detali - a to znowu ten
błąd.

Zamotany ten opis, ale wkurzam się, że i AnyDAC jak i DevExpress olewają
tę sytuację zwalając winę a drugich.

jh


jh

unread,
Mar 3, 2012, 9:05:53 AM3/3/12
to
I tak gwoli ścisłości do opisu:
http://www.devexpress.com/Support/Center/p/B221767.aspx

Pod ostatnią odpowiedzią jest screenshot, gdzie widać ten błąd. Z DB
Layout też miałem rację, że jest bug:

http://www.devexpress.com/Support/Center/p/B212876.aspx

jh

jh

unread,
Mar 3, 2012, 2:56:56 PM3/3/12
to
W dniu 03.03.2012 15:05, jh pisze:
> http://www.devexpress.com/Support/Center/p/B221767.aspx


Dobre tyle, że AnyDAC potwierdził, że problem istnieje...

jh

jh

unread,
Mar 3, 2012, 4:15:48 PM3/3/12
to
W dniu 03.03.2012 20:56, jh pisze:
> Dobre tyle, że AnyDAC potwierdził, że problem istnieje...

No i problem rozwiązany. Relacja master-detail była zdefiniowana
dwukrotnie - między komponentami AnyDAC i w gridzie. Przeoczyłem przede
wszystkim ja, ale i support DevExa. Uff :)

jh

R.e.m.e.K

unread,
Mar 4, 2012, 6:54:04 AM3/4/12
to
Dnia Sat, 03 Mar 2012 22:15:48 +0100, jh napisał(a):

> No i problem rozwiązany. Relacja master-detail była zdefiniowana
> dwukrotnie - między komponentami AnyDAC i w gridzie. Przeoczyłem przede
> wszystkim ja, ale i support DevExa. Uff :)

Sam to odkryles czy autor AnyDACa pomogl?

--
pozdro
R.e.m.e.K

jh

unread,
Mar 4, 2012, 7:48:28 AM3/4/12
to
W dniu 04.03.2012 12:54, R.e.m.e.K pisze:
Support AnyDACa. Mnie się wydawało, że to jest tak, że jak ustawię w
gridzie DetailsInSQLMode na true, to znaczy, że grid o to nie dba i
muszę tę relację zdefiniować pomiędzy datasetami i tam obsłużyć parametr
wiążący klucz obcy. A to głównie dlatego, że wszelkie ich przykłady
opierały się na datasetach, w których nie ma MasterSource. Z kolei dla
innych gridów, owe MasterSource powinno być ustawione, żeby m-d działały
i stąd problem. A że dawno do DevExa nie sięgałem to i zapomniałem.

jh
0 new messages