2012-11-22 9 views
8

Precis: Mój kod próbuje zaktualizować pola niefizyczne w Delphi XE TClientDataset (podłączony do TSQLQuery z zestawem SQL nieruchomości), które zostały utworzone w wyniku wykonania komendy runtime Open.muszę uniknąć próby aktualizacji pola niefizycznych w Delphi TClientDataset podłączone do TSQLQuery

Mam TClientDataset podłączony do TDatasetProvider podłączonego do TSQLQuery podłączonego do TSQLConnection. Pierwsze trzy z tych obiektów są zawarte w kilku klasach w bibliotece, z której korzystam w wielu miejscach w kilku projektach. Te klasy tworzą te 3 obiekty w czasie wykonywania i eliminują znaczną ilość powtarzających się kodów, niezbędnych, ponieważ mam wiele, wiele z tych tripletów.

Dość typowo będę załadować TClientDataset z bazy danych, określając pewne SQL w majątku TSQLQuerySQL i nazywając Open na TClientDataSet. Fields w TClientDataset są tworzone za pośrednictwem tego połączenia do Open tj.. nie istnieją przed Open.

Wystąpił problem w sytuacji, gdy trzy pola wygenerowane w TClientDataset są niefizyczne; to jest, SQL wykonuje obliczenia, aby je wygenerować. Niestety w TClientDataset te 3 pola nie są tworzone inaczej niż pola fizyczne; ich FieldKind jest fkData (idealnie byłoby fkInternalCalc), Calculated nieruchomość jest False (idealnie byłoby True) i ich ProviderFlags obejmują pfInUpdate (który idealnie nie powinien on). Nic dziwnego, że kiedy nadejdzie czas, aby zrobić ApplyUpdates na TClientDataset jest wyjątek ...

Project XXX.exe raised exception class TDBXError with message 
SQL State: 42S22, SQL Error Code: 207 Invalid column name 'Received'. 
SQL State: 42S22, SQL Error Code: 207 Invalid column name 'Issued'. 
SQL State: 42S22, SQL Error Code: 207 Invalid column name 'DisplayTime'. 

mogę uniknąć tego błędu, usuwając tych dziedzinach za pfInUpdate flagi obsługi OnUpdateData Event TDatasetProvider „s. Jednak to rozwiązanie wymaga, aby określone nazwy pól były znane tej funkcji, która znajduje się w klasach ogólnych wspomnianych powyżej, tym samym przełamując ogólność kodu.

To, czego szukam, to ogólny sposób sygnalizowania obliczonej natury tych pól funkcji funkcji obsługi zdarzeń.

nie mogą zmienić FieldKind lub Calculated właściwości (na fkInternalCalc i True odpowiednio), po wywołaniu Open ponieważ generuje komunikat WorkCDS: Cannot perform this operation on an open dataset wyjątku. Nie mogę zmienić tych właściwości przed wywołaniem Open, ponieważ Fields jeszcze nie istnieje.

mogę usunąć flagę pfInUpdate z ProviderFlags właściwości te Field „s po Open ale to nie przejdzie na«Delta»TClientDatset że przybędzie obsługi OnUpdateData zdarzeń. Próbowałem również ustawić właściwości pola FieldDefs.InternalCalcField; znowu to nie zostanie przekazane do zbioru danych Delta.

Tak więc wszystkie pomysły sygnalizacyjne, które próbowałem, nie zadziałały. Byłbym wdzięczny za wszelkie nowe pomysły lub alternatywne podejście.

Wszystkie wyniki wyszukiwania internetowego, które spotkałem - w tym doskonałe artykuły Cary'ego Jensena - dotyczą konfiguracji generowanych w czasie projektowania lub innych niż SQL, które nie mają zastosowania w mojej sytuacji.

+0

Czy twój komponent pochodzi z TClientDataSet lub jest kompozycją? – jachguate

+0

Mam nadzieję, że zrozumiałem twoje pytanie. Te dwie klasy, o których wspomniałem, nie są same w sobie komponentami, zawierają raczej klasy TClientDataSet, TDataSetProvider i TSQLQuery, z których żadna nie jest pochodna. nie subklasowane. Z dwóch klas jedna pochodzi od drugiej, ale klasa podstawowa tych dwóch wywodzi się z TObject. –

+0

W jaki sposób otwierasz wewnętrzny zestaw ClientDataSet? Mam na myśli, czy wywołujesz metodę na swojej klasie lub bezpośrednio wywołujesz wewnętrzną metodę ClientDataSet.Open? – jachguate

Odpowiedz

5

Możesz utworzyć mechanizm w swojej klasie, aby wstępnie skonfigurować ProviderFlags dla poszczególnych pól, które chcesz zignorować w procesie aktualizacji.

Zgodnie z komentarzem do twojego pytania, sugeruję, aby utworzyć nową metodę w klasie, aby otworzyć wewnętrzny ClientDataSet, cała magia będzie miała miejsce w tej metodzie.

Po pierwsze, jednym prostym mechanizmem jest dołączenie nowej właściwości TStringList, która zawiera listę wszystkich pól, które mają zostać zignorowane, aby dopasować je według nazwy. Możesz to zaadaptować lub stworzyć nowy lepszy mechanizm, ważne jest to, że jesteś w stanie określić, które pola chcesz skonfigurować w ten sposób.

Weź to jako pomysł.

Napisałem tutaj cały kod, może składnia jest zła, ale pokazuje cały pomysł.

+0

Zasada stojąca za tym pomysłem jest poprawna i odpowiada moim potrzebom sygnalizacyjnym. Jednak, jak wspomniałem w poprzednim komentarzu, wyjątek występuje podczas 'ApplyUpdates' zamiast podczas wywoływania' Open'. Aby użyć powyższego rozwiązania, użyłbym twojej właściwości 'UpdateIgnoredFields' w procedurze obsługi zdarzeń' OnUpdateData' TDataSetProvider, ponieważ 'Open' działa na całym zestawie danych, podczas gdy' OnUpdateData' działa na zbiorze danych "Delta". Wielkie dzięki za Twoją pomoc. Przykro mi, że nie mogę cię głosować, moja "reputacja" jest niewystarczająca :-) –

+0

@Chris, przedstawione podejście tylko zapobiega wyjątkowi w czasie ApplyUpdates. Usuwając flagę pfInUpdate. Teraz, gdy myślę o tym nieco więcej, trzeba usunąć także flagę pfInWhere. Po prostu spróbuj, a zobaczysz, jak to działa. – jachguate

+0

Masz rację co do potrzeby usunięcia flagi pfInWhere. Jednak nie działa to, aby wyczyścić ProviderFlags na głównym ClientDataSet - próbowałem tego bez powodzenia na wczesnym etapie testowania - działa on tylko na zbiorze danych "Delta". Powodem jest to, że chociaż można wyczyścić flagi na głównym zestawie danych, nie zostanie to zasygnalizowane zestawowi danych "Delta", który nadal ma ustawione flagi. Próbowałem prześledzić VCL, ale nie mogłem znaleźć "rozłączenia", ale z pewnością nie działa. Stąd potrzeba tego w procedurze obsługi zdarzeń OnUpdateData, która zajmuje się tylko zbiorem danych delta. –

1

można przekazać ProviderFlags (jak również kilka innych właściwości) od klienta do dostawcy (delta), ustawiając odpowiednie opcjonalne parametry na CDS. nie zapomnij ustawić parametru IncludeInDelta param

Powiązane problemy