I've been using the Xdata web core demo for blobs to try and implement this (I'd have thought that this would be just a built in method for TXDataWebDataset - maybe I'll add a request).
Anyway:
my entity is:
{$SCOPEDENUMS ON}
[Enumeration(TEnumMappingType.emString, 'PlainText,MarkDown')]
TsxeNoteFormat = (PlainText, MarkDown);
{$SCOPEDENUMS OFF}
[Entity]
[AutoMapping]
[Table('NOTES')]
[DBIndex('IX_NOTE_ENTITY', 'ENTITY_CLASS_NAME,ENTITY_ID')]
[Sequence('SEQ_NOTE', 1, 1)]
[Id('FId', TIdGenerator.IdentityOrSequence)]
TsxeNote = class(TSMXBaseEntity)
private
FId: Integer;
FDateAdded: TDateTime;
FAddedBy: Integer;
FLastUpdatedBy: NullableInteger;
FLastUpdated: NullableDateTime;
[Column('ENTITY_CLASS_NAME', [], 64)]
FEntityClassName: string;
[Column('ENTITY_ID')]
FEntityId: Integer;
[Column('TITLE', [], 255)]
FTitle: string;
[Column('NOTE', [TColumnProp.Lazy])]
[DBTypeWideMemo]
FNote: TBlob;
FNoteFormat: TsxeNoteFormat;
public
property Id: Integer read FId write FId;
property DateAdded: TDateTime read FDateAdded write FDateAdded;
property AddedBy: Integer read FAddedBy write FAddedBy;
property LastUpdated: NullableDateTime read FLastUpdated write FLastUpdated;
property LastUpdatedBy: NullableInteger read FLastUpdatedBy write FLastUpdatedBy;
property EntityClassName: string read FEntityClassName write FEntityClassName;
property EntityId: Integer read FEntityId write FEntityId;
property Title: string read FTitle write FTitle;
property Note: TBlob read FNote write FNote;
property NoteFormat: TsxeNoteFormat read FNoteFormat write FNoteFormat;
end;
On my Webform I have a TXDataWebDataset with all the fields retrieved from the server app at design time, except for the Note field which is added as
NotesDatasetNotexdataproxy: TMemoField;
FieldName = Note@xdata.proxy
In code, when a note is saved it first calls
[Async]
procedure SaveNote;
The blob saving is pretty much a straight lift from the demo. NoteData is a TWebMemo control.
procedure TEssentialsNotesForm.SaveNote;
var
xhr: TJSXmlHttpRequest;
Info: TResolveResults;
isNew: Boolean;
updateStatus: TUpdateStatus;
function strEncodeUTF16(str: string): TJSArrayBuffer;
var
BufView: TJSUInt16Array;
I: Integer;
begin
Result := TJSArrayBuffer.new(Length(str) * 2);
BufView := TJSUInt16Array.new(Result);
for I := 0 to Length(str) - 1 do
BufView[I] := TJSString(str).charCodeAt(I);
end;
begin
FIsSaving := True;
try
//Save the record
if TXDataDSUtils.CheckIsModified(NotesDataset) then
begin
isNew := False;
Info := Await(NotesDataset.ApplyUpdatesAsync);
updateStatus := Info.Records[0].Status;
if Info.Records[0].Status = TUpdateStatus.usInserted then
begin
isNew := True;
TXDataDSUtils.UpdateId(NotesDataset, Info, 'Id', 0);
end;
end;
//Now save the blob
if (isNew and (NoteData.Text <> '')) or NoteData.Modified then
begin
Assert(NotesDatasetId.Value > 0);
xhr := TJSXMLHttpRequest.new;
xhr.open('PUT',
NotesDataset.Connection.URL + '/' +
string(TJSObject(NotesDataset.CurrentData)['Note@xdata.proxy'])
);
xhr.send(strEncodeUTF16(NoteData.Lines.Text));
end;
finally
FIsSaving := False;
end;
end;
The problem I have at the moment is that when a new record is saved (I haven't got as far as having a record in the dataset to edit it yet).
NotesDataset.ApplyUpdatesAsync()
but the server raises the exception
ExceptionMessage="Expected DoubleQuoted but was Null at path $.Note@xdata.proxy"
ExceptionName="EInvalidStateException"
ExceptionDisplayName="EInvalidStateException"
The demo doesn't seem to allow adding a new record, but that could just be me.
What do I need to do here?
