Autor Beitrag
Slipstream
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 26
Erhaltene Danke: 5



BeitragVerfasst: Mi 19.04.17 16:51 
Ich muss derzeit eine VCL-Anwendung mit XE7 nach FMX portieren. In der Datenbank gibt es eine Kundentabelle mit den Feldern Vor- und Nachname, die als Foreign Keys auf die beiden Tabellen VORNAMEN und NACHNAMEN verweisen. Für den Fall, dass der Anwender einen Namen eingibt, der in einer der Vorgabetabellen noch nicht existiert, habe ich diese Vorkehrung getroffen:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
function TDataModul1.GetIdOfVorname(const AName : Stringconst Sex : Integer) : Integer;
begin
  if (AName = ''or (AName = '-'then
     Result := 0                   else
  begin
    if not Qset_Vornamen.Locate('VORNAME;GESCHLECHT',VarArrayOf([AName,Sex]),[]) then
    begin
      Qset_Vornamen.Append;
      Qset_Vornamen.FieldByName('VORNAME').AsString := AName;
      Qset_Vornamen.FieldByName('GESCHLECHT').AsInteger := Sex;
      Qset_Vornamen.Post;
    End;
    Result := Qset_Vornamen.FieldByName('ID_VORNAMEN').AsInteger;
  end;
end;

Wenn der Vornamenstring leer ist oder nur aus '-' besteht, soll die Id mit dem Wert 0 zurückgeliefert werden. Ansonsten soll geprüft werden, ob der Datensatz bereits existiert. Wenn ja, soll die zugehörige Id zurückgegeben, wenn nicht, der Datensatz neu angelegt werden.

Der Anwender gibt zB "Manuela" als Vorname ein und wählt das Geschlecht "weiblich". Dieser Eintrag existiert schon in der Tabelle VORNAMEN. Dennoch versucht das Programm, diesen Datensatz neu anzulegen, was selbstverständlich einen Constraint-Error in der Datenbank auslöst. Ich verstehe nicht, weshalb die Locate-Methode den vorhandenen Datensatz nicht findet. Mit VCL funktioniert diese Methode correct. Mit FMX shinebar nicht.

Workarround mit SQL funktioniert dagegen problemlos:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
  if (AName = ''or (AName = '-'then
     Result := 0                   else
  begin
    QueryMain_Clear;
    QueryMain.SQL.Append('select * from VORNAMEN');
    QueryMain.SQL.Append('where VORNAME = ' + QuotedStr(AName));
    QueryMain.SQL.Append('and');
    QueryMain.SQL.Append('GESCHLECHT = ' + IntToStr(Sex));
    QueryMain.Open;
    If QueryMain.RecordCount = 0 then
       Result := 0               else
       Result := QueryMain.FieldByName('ID_VORNAMEN').AsInteger;
    QueryMain_Clear;
  end;


Da sind noch mehr solcher Abfrage- und Insert-Methoden, die funktionieren alle auf die gewohnte Wise. Der einzige Unterschied: Es wird nur ein Feld abgefragt, VarArrayOf wird in den funktionierenden Methoden nicht benötigt.
Sinspin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1321
Erhaltene Danke: 117

Win 10
RIO, CE, Lazarus
BeitragVerfasst: Mi 19.04.17 18:08 
Ob ein Locate geht oder nicht, hängt nicht davon ab was für eine Technik Du für die Oberfläche verwendest.

Da Du wie es scheint schon eine Query verwendest um das Locate auszuführen wäre auch interessant wie das Script bisher aussieht damit überhaupt Daten kommen.
Ehrlich gesagt würde ich immer deinen Workaround, also die direkte Query, zur Abfrage vorziehen.
Allerdings nicht mit 'SELECT * ...', sondern 'SELECT ID_VORNAMEN ...'.

Hat sich mit der Umstellung auf FMX vieleicht auch die DB Technik geändert? Wird jetzt ein ODBC Treiber verwendet?

_________________
Wir zerstören die Natur und Wälder der Erde. Wir töten wilde Tiere für Trophäen. Wir produzieren Lebewesen als Massenware um sie nach wenigen Monaten zu töten. Warum sollte unser aller Mutter, die Natur, nicht die gleichen Rechte haben?
Slipstream Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 26
Erhaltene Danke: 5



BeitragVerfasst: Mi 19.04.17 19:47 
user profile iconSinspin hat folgendes geschrieben Zum zitierten Posting springen:
Ob ein Locate geht oder nicht, hängt nicht davon ab was für eine Technik Du für die Oberfläche verwendest.

Das verstehe ich nicht: Was hat das Funktionieren von Locate mit der Oberfläche (was meinst du mit "Oberfläche" eigentlich genau?) oder mit der "Technik für die Oberfläche" zu tun? Die DB-Abfrage findet im Datenmodul statt.

user profile iconSinspin hat folgendes geschrieben Zum zitierten Posting springen:
Da Du wie es scheint schon eine Query verwendest um das Locate auszuführen wäre auch interessant wie das Script bisher aussieht damit überhaupt Daten kommen.
Ehrlich gesagt würde ich immer deinen Workaround, also die direkte Query, zur Abfrage vorziehen.
Allerdings nicht mit 'SELECT * ...', sondern 'SELECT ID_VORNAMEN ...'.

Es scheint nicht nur so, ich verwende tatsächlich eine Query-Komponente, nein, sogar mehrere. Welche DBAccess-Komponente würdest du denn stattdessen vorschlagen?

Welches "Script" meinst du denn?
Worin soll der Unterschied zwischen 'SELECT * ...', und 'SELECT ID_VORNAMEN ...' bestehen, wenn ich ohnehin alle Felder benötige?

user profile iconSinspin hat folgendes geschrieben Zum zitierten Posting springen:
Hat sich mit der Umstellung auf FMX vieleicht auch die DB Technik geändert? Wird jetzt ein ODBC Treiber verwendet?

Genau deshalb frage ich ja: Wenn ich ein Query.Locate ohne VarArrayOf mache, weil ich nur ein Feld vergleich muss, functioniert die Function. Benötige ich mehrere Felder und muss daher ein VarArrayOf verwenden, functioniert die Function nicht.

Wie es scheint, kennst du dieses Fehlverhalten nicht. Vielleicht findet sich noch ein User hier, der damit Erfahrung hat.
Sinspin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1321
Erhaltene Danke: 117

Win 10
RIO, CE, Lazarus
BeitragVerfasst: Do 20.04.17 13:22 
user profile iconSlipstream hat folgendes geschrieben Zum zitierten Posting springen:
Das verstehe ich nicht: Was hat das Funktionieren von Locate mit der Oberfläche (was meinst du mit "Oberfläche" eigentlich genau?) oder mit der "Technik für die Oberfläche" zu tun? Die DB-Abfrage findet im Datenmodul statt.

Hmmm :gruebel: kann ich kein Deutsch mehr?
Genau das habe ich doch geschrieben. VCL/FMX sollte keinen Unterschied machen.

user profile iconSlipstream hat folgendes geschrieben Zum zitierten Posting springen:
Es scheint nicht nur so, ich verwende tatsächlich eine Query-Komponente, nein, sogar mehrere. Welche DBAccess-Komponente würdest du denn stattdessen vorschlagen?

Was für eine DB verwendest Du? Sind das Delphi standard Komponenten? Nenn mal bitte den Name der Klasse.

user profile iconSlipstream hat folgendes geschrieben Zum zitierten Posting springen:
Welches "Script" meinst du denn?
Worin soll der Unterschied zwischen 'SELECT * ...', und 'SELECT ID_VORNAMEN ...' bestehen, wenn ich ohnehin alle Felder benötige?

In Deinem Beispiel sieht es nicht so aus als wenn Du alle Felder brauchen würdest. Daher mein Vorschlag das einzuschränken. Ansonsten macht das natürlich keinen Sinn.

user profile iconSlipstream hat folgendes geschrieben Zum zitierten Posting springen:
Genau deshalb frage ich ja: Wenn ich ein Query.Locate ohne VarArrayOf mache, weil ich nur ein Feld vergleich muss, functioniert die Function. Benötige ich mehrere Felder und muss daher ein VarArrayOf verwenden, functioniert die Function nicht.

Das ist nicht die Antwort auf meine Frage, verwendest Du jetzt einen ODBC Treiber? ...und vorher nicht?

user profile iconSlipstream hat folgendes geschrieben Zum zitierten Posting springen:
Wie es scheint, kennst du dieses Fehlverhalten nicht. Vielleicht findet sich noch ein User hier, der damit Erfahrung hat.

Nein, ich kenne das Verhalten nicht. Ich kenne aber Fälle in denen es passieren kann dass solche ein Verhalten auftritt. Ich würde eher in der DB oder Zwischenschicht suchen wenn es vorher ging. Index weg? Index anders? DB neu erstellt?

Also, nochmal die wesentliche Frage, wie sieht das SQL Statement aus mit dem Du die Query aufmachst BEVOR Du versuchst mit Locate einen Datensatz zu finden?

Übrigens kannst Du statt Locate auch einen Filter verwenden. Dann siehst Du gleich wieviele Datensätze wirklich die Bedingung erfüllen. Locate ändert den Zeiger ja nur auf den ersten gefundenen.

_________________
Wir zerstören die Natur und Wälder der Erde. Wir töten wilde Tiere für Trophäen. Wir produzieren Lebewesen als Massenware um sie nach wenigen Monaten zu töten. Warum sollte unser aller Mutter, die Natur, nicht die gleichen Rechte haben?
Slipstream Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 26
Erhaltene Danke: 5



BeitragVerfasst: Do 20.04.17 14:38 
Sorry, Sinspin, ich wusste nicht, was du mit Oberfläche meintest. Hier sagen wir Oberfläche für die GUI. VCL und FMX sind bei uns verschiedene Komponentenpaletten.

Es sollte wirklich keinen Unterschied machen, ob VCL oder FMX, aber es macht einen Unterschied, wie ich schon beim letztenmal geschrieben habe: Unter FMX functioniert die Locate-Methode nur zum localisieren eines Feldes, bei zwei und mehr Feldern muss VarArrayOf verwendet werden, und dann findet der/die/das Query den Eintrag nicht. Ich würde jetzt gerne wissen, ob dieser Fehler bei neueren Delphi-Versionen als XE7 ausgebügelt wurde.

user profile iconSinspin hat folgendes geschrieben Zum zitierten Posting springen:
Also, nochmal die wesentliche Frage, wie sieht das SQL Statement aus mit dem Du die Query aufmachst BEVOR Du versuchst mit Locate einen Datensatz zu finden?


select * from ...

Gebe ich die einzelnen Felder statt * an, ändert sich dadurch gar nichts: Die Locate-Methode functioniert auch dann nicht correct.

user profile iconSinspin hat folgendes geschrieben Zum zitierten Posting springen:
Übrigens kannst Du statt Locate auch einen Filter verwenden. Dann siehst Du gleich wieviele Datensätze wirklich die Bedingung erfüllen. Locate ändert den Zeiger ja nur auf den ersten gefundenen.


Ich weiss genau, dass immer nur ein Datensatz die Bedingung erfüllen kann. Doppelte Einträge werden durch die Indexierung verhindert. Ich bleibe jetzt bei der SQL-Abfrage und möchte eigentlich nur wissen, ob dieser Fehler bei Versionen neuer als XE7 behoben wurde.

Es gibt noch viele mehr solcher Ungereimtheiten bei FMX. Ich glaube fast, das FMX ist bei XE7 noch sehr buggy. Wenn ich nur wusste, ob die neue Version Tokio diese Fehler nicht mehr hat, würde ich meinen Chef dazu überreden, die zu kaufen. Andernfalls müssen wir vielleicht mit Lazarus weitermachen. Dann haben wir aber wieder andere problems.