Hallo zusammen,
eigentlich wollte ich hier von meinem Problem berichten und nachfragen, ob da jemand was zu weiß.
Inzwischen habe ich aber schon selber herausgefunden, was da schief gegangen ist
Da der eigentliche "Fehler" aber so überhaupt nichts mit der Fehlermeldung zu tun hat, habe ich mich entschlossen
das hier für "die Nachwelt" zu dokumentieren - vielleicht hat ja mal jemand ein ähnliches Problem und stolpert bei der Suche hier drüber
Ausgangspunkt: ich greife mit Delphi7 über die
BDE-Klassen (TDatabase, TQuery, etc.) auf eine MS-
SQL Server Datenbank zu (v2019).
Auf der Maske liegt ein TQuery
qryTest, das einen Datensatz aus einem nicht aktualisierbaren Datenbankview
V_Test liest;
damit ich auch Datenänderungen in der zugehörigen Tabelle
T_Testspeichern kann, ist am TQuery ein UpdateObject
updTest angehängt.
Hier mal beispielhaft, wie die
SQL-Statements dazu aussehen:
Auf der Datenbank sieht es dann (beispielhaft) so aus:
Code:
CREATE TABLE [Test] (
[ID] [INT] IDENTITY( 1, 1 ) NOT NULL
, [Name] [VARCHAR]( 50 ) NOT NULL
, [Info] [VARCHAR]( 100 ) NULL
, [Text] [VARCHAR]( 2048 ) NULL
, CONSTRAINT [PK_Test] PRIMARY KEY CLUSTERED (
[ID] ASC
)
)
GO
CREATE OR ALTER VIEW [V_Test]
AS
SELECT [ID]
, TRIM( [Name] ) AS [Name]
, UPPER( TRIM([Info]) ) AS [Info]
, TRIM( [Text] ) AS [Text]
FROM [T_Test]
GO
(mir ist natürlich klar, dass dieser hier beschriebene einfache View auch direkt aktualisierbar wäre - er soll hier aber als Beispiel dienen;
also: nehmen wir mal an, dass der View nicht editierbar wäre...)
Im Delphi-Code steht dann folgendes
SQL-Statement beim
qryTest:
Code:
SELECT [ID]
, [Name]
, [Info]
, [Text]
FROM [V_Test]
WHERE [ID] = :ID
Und im
updTest-Objekt steht als
Update-
SQL:
Code:
UPDATE [T_Test]
SET [Name] = TRIM( :Name )
, [Info] = UPPER( TRIM(:Info) )
, [Text] = TRIM( :Text )
WHERE [ID] = :OLD_ID
In der Delphi-Maske
frmTest.dfm sieht es (auszugsweise) folgendermaßen aus:
Delphi-Quellcode:
object qryTest: TQuery
AutoCalcFields = False
DatabaseName = '
DB'
FilterOptions = [foCaseInsensiteive, foNoPartialCompare]
SQL.Strings = (
'
SELECT [ID]'
'
, [Name]'
'
, [Info]'
'
, [Text]'
'
FROM [V_Test]'
'
WHERE [ID] = :ID')
UpdateMode = upWhereKeyOnly
UpdateObject = updTest
ParamData = <
item
DataType = ftInteger
Name = '
ID'
ParamType = ptInput
Value = 0
end>
object qryTestID: TIntegerField
FieldName = '
ID'
ProviderFlags = [pfInWhere, pfInKey]
ReadOnly = True
DisplayFormat = '
0'
end
object qryTestName: TStringField
FieldName = '
Name'
ProviderFlags = [pfInUpdate]
Size = 50
end
object qryTestInfo: TStringField
FieldName = '
Info'
ProviderFlags = [pfInUpdate]
Size = 100
end
object qryTestText: TMemoField
DisplayWidth = 254
FieldName = '
Text'
ProviderFlags = [pfInUpdate]
OnGetText = qryTestText_GetText
BlobType = ftMemo
GraphicHeader = False
Size = 1
end
end
Die Methode ist nur dazu da, dass nur ein Teil des (langen) Textes dargestellt wird (ich weiß nicht, ob das für den Fehler relevant ist - habe es der Vollständigkeit halber dargestellt):
Delphi-Quellcode:
procedure qryTestText_GetText(
fldSender_ : TField;
var sText_ : String;
bDisplayText_ : Boolean );
begin
sText_ := EmptyStr;
if ( NOT qryTest.Active ) then begin
Exit;
end;
if ( qryTestText.IsNull ) then begin
Exit;
end;
sText_ := Copy( qryTestText.AsString, 1, 254 );
end;
gespeichert wird ein Datensatzes mit folgenden Zeilen:
Delphi-Quellcode:
if ( NOT dbConn.InTransaction ) then begin
dbConn.StartTransaction();
end;
if ( qryTest.CachedUpdates ) then begin
qryTest.ApplyUpdates();
end;
dbConn.Commit();
if ( qryTest.CachedUpdates ) then begin
qryTest.CommitUpdates();
end;
(dbConn ist das
TDatabase-Objekt)
Dabei kommt in der Zeile mit dem
ApplyUpdates()-Aufruf eine
Exception:
Table is read only. (addr=0x4085BE42);
Im Call-Stack steht als unterstes die Klasse
DBTables und dort die Methode
DbiError()
Ich habe mir jetzt den Wolf gesucht, warum das wohl auftritt - ich habe sogar testweise den
SQL-Select soweit umgebaut, dass ich ihn direkt auf der Tabelle statt dem View machen kann...
...keine Änderung - Fehlermeldung kam trotzdem