Niesforna konwersja StrToInt

0

Pobieram z tabeli pole typu INTEGER o zawartości równej 13. (ilosc INTEGER;) na kilka sposobów z różnym skutkiem:

ilosc:=f_produkty.t_specyfikacje_zamowien.FieldByName('ilosc').AsInteger;

wynikiem jest 0

ilosc:=StrToInt(f_produkty.t_specyfikacje_zamowien.FieldValues['ilosc']);

wynikiem jest 0

ilosc_string:=f_produkty.t_specyfikacje_zamowien.FieldValues['ilosc'];

wynikiem jest '13'

Niby mam 13, ale to wciąż nie integer. Po operacji StrToInt(ilosc_string) wynikiem znowu jest 0 ;-(

0
ilosc:=f_produkty.t_specyfikacje_zamowien.FieldByName('ilosc').AsInteger;

tak jest poprawnie baza zwraca ci <ort>Od razu </ort>wartość integer, jesli zwraca 0 a w bazie jest 13 to znaczy ze w bazie jest zapisany nie jako integer

0

Sęk w tym, że w bazie jest zapisane jako integer :/

user image

0

Co to za baza? Miałem taką sytuację w interbase. Poprawiło się gdy zmieniłem konfigurację i dałem Page Buffers zamiast zero na 50000.

0

To właśnie Interbase. u Mnie Page Buffers jest ustawiona na 2048. Zmiana na 50000 niestety nie pomaga :(

user image

0

Może po prostu jest błąd w programie?
Przejdź krokowo program ("trace into") i w pobliżu zapisu i odczytu tej wartości porównaj jaka ona jest poprzez odczytanie jej z IBConsole. Miałem taką sytuację, że użyłem tej samem funkcji delphi w dwóch miejscach "żeby było szybciej". W jednym miejscu ona zerowała pewną zmienną a w innym nie miała zerować. Zapomniałem o tym, że funkcja zeruje tą zmienną i w drugim miejscu spowodowało to nieprawidłowe zerowanie.

Druga możliwość jest taka, że nie użyłeś transakcji. W interbase transakcji musi się używać RÓWNIEŻ jeśli tylko odczytujemy z bazy. Dajemy więc przy odczycie

try
TSQLConnection.StartTransaction
odczytujemy z bazy
finally
TSQLConnection.Commit
end

Przy zapisie trzeba dodatkowo dodać Rollback w bloku try except i w razie pojawienia się wyjątku powtórzyć pętlę aż nie będzie wyjątku. W ten sposób postępujemy przy każdym rodzaju baz SQL. Chodzi tu o zamianę równoległego zapisu do tego samego rekordu bazy (przez kilku użytkowników jednocześnie) na zapis szeregowy, czyli żeby transakcje nie zachodziły na siebie. Problem zachodzenia na siebie transakcji i otrzymywania przez to nieprawidłowych odczytów jest na tyle uciążliwy że ustawiam maksymalny poziom izolowania transakcji czyli:

var
TD: TTransactionDesc;


UdanyZapis:=False;
ProbaZapisu:=0;
TD.TransactionID := 1;
TD.IsolationLevel := xilREPEATABLEREAD;
repeat
try
UserSession.GraW16Connection.StartTransaction(TD);
ProbaZapisu:=ProbaZapisu+1;
//tutaj następują odczyty i zapisy do bazy
...........
UserSession.GraW16Connection.Commit(TD);
UdanyZapis:=True

except
  UserSession.GraW16Connection.Rollback(TD);
  sleep(random(5))
end;

until UdanyZapis or (ProbaZapisu>=LiczbaProbZapisu);

0

Bardzo dziękuje za zaangażowanie Panie Mariuszu. Boję się jednak, że niektórych rzeczy wciąż nie rozumiem, mam wrażenie że Interbase ciągle rzuca mi kłody pod nogi, a nie mam już możliwości zmiany bazy ani nawet komponentów, bo aplikacja jest zbyt zaawansowana, a mnie goni termin jej oddania :/

Ale do rzeczy: nie używam komponentów z zakładki dbexpress a jedynie tych z zakładki Interbase. Czyli z tabelą łączę się za pomocą komponentów: IBDataBase->IBTransaction->IBTable

Mam również problemy z zaimplementowaniem Pańskiego rozwiązania do mojej procedury, dlatego bardzo prosiłbym o rzucenie na nią okiem i udzielenie mi przykładu, będę bardzo zobowiązany:

P.S.
Oczywiście prześledziłem ją krok po kroku wcześniej.

procedure Tf_zamowienia.b_zatw_zam_dla_sprzClick(Sender: TObject);
var id_zam, id_prod, nazwa, ilosc_str:string;
    ilosc:integer;
    
begin
id_zam:=grid_zamowienia.Fields[0].AsString;

f_produkty.t_specyfikacje_zamowien.First;
while not f_produkty.t_specyfikacje_zamowien.EoF do
  begin
    if f_produkty.t_specyfikacje_zamowien.FieldValues['id_zamowienia']=id_zam then //wartosc char zostaje prawidłowo pobrana i warunek działa poprawnie
      begin
        id_prod:=f_produkty.t_specyfikacje_zamowien.FieldValues['id_produktu']; //i tutaj poprawnie pobrana zostaje wartosc char 
        ilosc:=f_produkty.t_specyfikacje_zamowien.FieldByName('ilosc').AsInteger; //tutaj jednak nieszczesny integer zamienia sie w 0, zamiast w 13
        //ilosc_str:=f_produkty.t_specyfikacje_zamowien.FieldValues['ilosc']; //dla przykladu w ten sposob otrzymuje wartosc 13, jednak typu string
      end;
    f_produkty.t_specyfikacje_zamowien.Next;
  end;

end;
0

Niestety nie mam doświadczenia z komponentami IBExpress więc nie jestem pewien jak to jest z transakcjami, czy należy tu używać TClientDataSet (które domyślnie obsługują transakcje) czy też wypisywać ustawiania parametrów, początek, zatwierdzenie i odwołanie transakcji w kodzie. Mogę ewentualnie podać namiar na archiwum i działające forum dyskusyjne interbase.

Pamiętam że miałem podobny problem na skutek nieprawidłowego odwoływania się do pól tabeli bazy.
Zamiast FieldByName('ilosc') napisz FieldByName('ILOSC') tak jak prawidłowo nazywa się pole, i wszędzie gdzie indziej tez tak pozamieniaj. Może to pomoże.

0

Duże litery też nie pomogły.

Poproszę namiar na to forum jeśli można

0
JacekKw napisał(a)

Duże litery też nie pomogły.

Poproszę namiar na to forum jeśli można

Archiwum wsześniejszych wypowiedzi jest w grupie dyskusyjnej borland.public.delphi.database.interbaseexpress

a teraz grupy dyskusyjne borlanda zostały przeniesione do forum dyskusyjnego i tam inżynierowie wolontariusze odpowiadają
https://forums.embarcadero.com/forum.jspa?forumID=108
Forum wymaga bezpłatnej rejestracji. Trzeba dosyć długo czekać na otwarcie tej strony, być może jest duże obciążenie serwera. Trzeba pisać w języku angielskim.

0
Mariusz Jędrzejowski napisał(a)
JacekKw napisał(a)

Duże litery też nie pomogły.

Jeszcze jedna sprawa. W zapytaniach sql też trzeba wszędzie pozamieniać małe litery na duże (najprościej całe zapytanie napisać dużymi literami).

0

Wielkie dzięki. Informacje na pewno się przydadzą. A teraz wieści z frontu.

Udało mi się obejść ten problem :)

Stworzyłem widok, w którym zebrałem dane z dwóch tabel, skracając tym sposobem trochę moją procedurę.

Pobierając dane z widoku nie doświadczyłem już problemów. Może to być spowodowane tym, że tworząc tabele nie używałem wielkich liter, zaś tworząc widok owszem, co by jednak wskazywało, że teoria małych liter jest jednak słuszna. Jak tylko wrócę z pracy, spróbuje sprawdzić czy to właśnie o to chodziło :)

Jeszcze raz wielkie dzięki [browar]

0

Ja bym tam w takiej sytuacji wolał sprawę wyjaśnić w 100%. A nie masz czasem pola ilosc w tym t_specyfikacje_zamowien zdefiniowanego jak String ? Czy w ogóle masz fieldsy zdefiniowane ? Jak klikniesz dwa razy na komponencie t_specyfikacje_zamowien i zaznaczysz ilosc to jakiego jest typu ?

b

0

Fieldsy definiowałem tworząc tabelę

CREATE TABLE specyfikacje_zamowien (
  ID_PRODUKTU VARCHAR(5) NOT NULL,
  ID_ZAMOWIENIA VARCHAR(5) NOT NULL,
  ILOSC INTEGER NOT NULL
);

Poniżej screen z object Inspectora. Nie widzę tam typu.

user image

Na 1 stronie tematu jest screen z Interbase'a potwierdzający typ pola.

0
JacekKw napisał(a)

Fieldsy definiowałem tworząc tabelę

CREATE TABLE specyfikacje_zamowien (
ID_PRODUKTU VARCHAR(5) NOT NULL,
ID_ZAMOWIENIA VARCHAR(5) NOT NULL,
ILOSC INTEGER NOT NULL
);

> 
> 
> Na 1 stronie tematu jest screen z Interbase'a potwierdzający typ pola.


Na wszelki wypadek sprawdziłbym przez skasowanie tej tabeli i odtworzenie z użyciem samych dużych liter w nazwie tabeli. 

Miałem kiedyś taką sytuację że w TSQLQuery (dbExpress) dałem, do właściwości SQL, select z małymi literami nazwy tabeli i pól tabeli i później właśnie takie zera mi wychodziły. 
Forum interbase jest też szybciej dostępne przez serwer grup dyskusyjnych forums.codegear.com
0

Witaj,

gdyby to nie kolidowało z pozostałym kodem użył bym funkcji StrToInt.
To byłoby najprostsze rozwiązanie.

0
JacekKw napisał(a)

Niby mam 13, ale to wciąż nie integer. Po operacji StrToInt(ilosc_string) wynikiem znowu jest 0

[!!!] Z tego wszystkiego to jest najbardziej zastanawiające, bo tutaj InterBase nie ma już nic do rzeczy.

Czy na pewno koledze chodziło o to co napisał ???

0
czytaczek napisał(a)
JacekKw napisał(a)

Niby mam 13, ale to wciąż nie integer. Po operacji StrToInt(ilosc_string) wynikiem znowu jest 0

[!!!] Z tego wszystkiego to jest najbardziej zastanawiające, bo tutaj InterBase nie ma już nic do rzeczy.

Czy na pewno koledze chodziło o to co napisał ???

Owszem. o to chodziło. To faktycznie jest zastanawiające. Można tylko zakładać, że pobrane '13' nie jest wcale wartością string, a jeszcze jakąś inną, skoro konwersja daje 0 ;)

0

Owszem ale wtedy powinno wywalić bład EConvertError
To się wydaje po prostu niemożliwe :|

0

<rozkłada ręce bezradnie>

0

Podążając za śladem dużych liter, jeśli utworzyłeś w programie stałe pola "persistent fields" to warto spróbować wszystkie je usunąć a następnie zaraz po tym z powrotem utworzyć. Utworzone events dla tych pól nie powinny zostać przez to skasowane. Takie odświeżenie często pomaga w różnych sytuacjach (jak przy zmianie typu pól bazy), więc może i tu pomoże.

0

witam,
choć osobiście pracuję na MS SQL 2005 Express i nie spotkałem takiej sytuacji, to problem jest ciekawy
pozdrawiam [browar]

0

Ciekawy oj ciekawy.

Do OP a może sprawdź jaki jest typ zwracany przez Value, chodzi mi o typ Varianta (VarType).

b

0

Odnoszę wrażenie, że to może być niewłaściwa obsługa transakcji. Miałem taką sytuację gdy nie używałem TClientDataSet i nie wpisywałem transakcji w kodzie dla odczytu danych. Nie wiemy jakich komponentów używasz i jak kodujesz zapis do bazy. Kiedyś był nieprawidłowy przykład "dpr examples" w którejś wersji dołączony do delphi odnośnie wykorzystania komponentów ibExpress i transakcja w nim trwała bardzo długo, może przez cały program. Później przeczytałem artykuł o TClientDataSet i komponentach dbExpress opisujących bardzo krótki czas przeznaczony na transakcję i przy okazji dbExpress ułatwia skalowalność, czyli zmianę bazy danych z interbase na inną, więc zostałem przy tym.

Przy testach wyszły też inne problemy z interbase 7,5. Nie mogłem ustawić poziomu izolowania transakcji snapshot globalnie w konfiguracji TSQLConnection bo to nie działało i wychodziły dziwne błędy. Musiałem ustawiać ten poziom przed każdą transakcją. Nie stanowi to problemu bo to jedna linijka dodatkowo, ale gdybym o tym nie wiedział, miałbym błędy.

1 użytkowników online, w tym zalogowanych: 0, gości: 1