To whom it may concern...
'Fehler' kann man es vielleicht nicht unbedingt nennen, etwas 'schlampig' bzw voreilig ist der JoinTest schon (zumindest mit
MSSQL und Provider SQLOLEDB). Hier der Original-Code aus IsJoinedRecordSet:
Delphi-Quellcode:
S:=VarToStr(RecordSet.Fields[0].Properties[cBaseTableName].Value);
For I:=Pred(RecordSet.Fields.Count) DownTo 1 Do With RecordSet.Fields Do
begin
If (S<>VarToStr(Item[I].Properties[cBaseTableName].Value)) Then Begin
Result:=jtJoined;
Break;
End;
Was ziemlich simpel darauf hinausläuft, dass bei einem Feld mit abweichendem Property 'BASETABLENAME' der JoinTest mit Ergebnis jtJoined beendet wird. Nun ist es aber so, dass vom Server berechnete Felder, zB mit folgendem SELECT (der zB verhindern soll, dass umfangreiche Memos oder Blobs für eine Gridanzeige tatsächlich geladen und zu einem client-seitigen Dataset transferiert werden):
SELECT ID, Name, [_Description] = CASE WHEN [Description] IS NULL THEN '<Memo>' ELSE '<MEMO>' END FROM ItemTable
in den Feld-Properties mit Value NULL (nach VarToStr also '') für BaseTableName geführt wird, der JoinTest also fälschlich jtJoined zurückgibt. Das kann man natürlich umgehen bzw 'austricksen', indem man die Unique_-Properties setzt, man könnte aber auch beim JoinTest selbst ansetzen, in diesem Fall und unter der Annahme, dass solcherart berechnete Felder immer mit einem Unterstrich beginnen zB so:
Delphi-Quellcode:
S := VarToStr(RecordSet.Fields[0].Properties[cBaseTableName].Value);
for I := pred(RecordSet.Fields.Count) downto 1 do
begin
SI := VarToStr(RecordSet.Fields.Item[I].Properties[cBaseTableName].Value);
if (S <> SI) and not ((SI = '') and (Pos('_',Fields[i].FieldName) = 1)) then
begin
Result := jtJoined;
Break;
end;
end;
Oder etwas allgemeingültiger und unter Berücksichtigung der Tatsache, dass der Treiber für die in Frage stehenden Felder auch die Property 'BASECOLUMNNAME' mit NULL zurückgibt:
Delphi-Quellcode:
S := VarToStr(RecordSet.Fields[0].Properties[cBaseTableName].Value);
for I := pred(RecordSet.Fields.Count) downto 1 do
begin
SB := VarToStr(RecordSet.Fields.Item[I].Properties[cBaseTableName].Value);
SC := VarToStr(RecordSet.Fields.Item[I].Properties[cBaseColumnName].Value);
if (S <> SB) and not ((SB = '') and (SC = '')) then
begin
Result := jtJoined;
Break;
end;
end;
Die entsprechenden Variablen und Konstanten sind natürlich zu definieren. Es empfiehlt sich auch, für jede Kombination von
DB und Treiber die Rückgabewerte der Properties nochmal gesondert zu untersuchen, wozu folgender Code dienen mag:
Delphi-Quellcode:
uses ..., ADO26_TLB, ...;
function VarToStrVerbose(const V: Variant): string;
begin
if VarIsEmpty(V) then Result := '<not assigned>'
else if VarIsArray(V) then Result := '<array>'
else if VarIsNull(V) then Result := '<null>'
else Result := VarToStr(V);
end;
procedure FieldProperties(ASet: TBetterADODataset; AList: TStrings; Index: integer=-1);
procedure FieldProps(ASet: TBetterADODataset; AList: TStrings; Index: integer);
var sN,sV: string;
vV: Variant;
i: integer;
begin
with ASet do
begin
for i:=0 to pred(RecordSet.Fields[Index].Properties.Count) do
begin
sN := RecordSet.Fields[Index].Properties[i].Name;
vV := RecordSet.Fields[Index].Properties[i].Value;
sV := VarToStrVerbose(vV);
AList.Add(sN+'='+sV);
end;
end;
end;
var i: integer;
begin
AList.Clear;
if (Index = -1) then
begin
for i:=0 to pred(ASet.Fields.Count) do
begin
AList.Add('['+ASet.Fields[i].FieldName+']');
FieldProps(ASet,AList,i);
AList.Add('');
end;
end else
begin
AList.Add('['+ASet.Fields[Index].FieldName+']');
FieldProps(ASet,AList,Index);
end;
end;
Der Code gibt eine INI-ähnliche Liste zurück, die mit den StringList-Eigenschaften Name und Value gut ausgewertet oder in einem Memo dargestellt werden kann. Auch sehr interessant ist nebenbei bemerkt das (prinzipiell gleiche) Auslesen der Properties des Connection- wie des RecordSet-Objektes. Dort wird bei besagtem Treiber übrigens im Zweifelsfall nicht NULL, sondern ein 'empty variant' für nicht gesetzte Werte zurückgegeben, daher der entsprechende Code in VarToStrVerbose.
Gruß an alle, Peinhard
P.S. Wenn das in die Code-Lib soll, bitte verschieben und/oder kurze Nachricht. Danke.