I wrote now the web application part of my solution.
Everything in general is working well, but now I stuck in the following problem:
In my web app I want to update an TKunde Object. The primary key is [uid] a TGuid field.
The logic should be: if the [uid] is null then insert a new record, if not then update the existing.
procedure TwmAdvoconto.wmAdvocontowaSendKundeAction(Sender: TObject; Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);var Serializer: TDataSnapJsonSerializer; Deserializer: TDataSnapJsonDeserializer; GetKundeObj, Kunde : TKunde; JSONValue: TJSONValue;begin Deserializer := TDataSnapJsonDeserializer.Create; Serializer := TDataSnapJsonSerializer.Create; Kunde := TKunde.Create; try try // Expect JSCON in TKunde Format JSONValue := TJSONObject.ParseJSONValue(Request.Content); if JSONValue<>nil then GetKundeObj := Deserializer.FromJson<TKunde>(JSONValue) else raise Exception.Create(STRINGISNULL); except on E : Exception do begin // JSON Error Response.Content := '{"'+JSONPARSINGERROR+'":"'+E.Message+'"}'; Exit; end; end; // we have a valid TKunde // write Kunde // Online Kunde Flag set //Kunde.OnlineKunde.Value := True; // Search Kunde Kunde := FRepository.GetKunde(GetKundeObj.uid); if Kunde = nil then Kunde := TKunde.Create; Kunde := GetKundeObj; FRepository.SaveKunde(Kunde); WriteLog('Save Kunde OK'); Response.Content := '{"OK":"'+GuidToJSONStr(Kunde.uid)+'"}'; WriteLog('{"OK":"'+GuidToJSONStr(Kunde.uid)+'"}'); finally Serializer.Free; Deserializer.Free; end; Handled := True;end;
if I try to do so I get this Error:
“Cannot turn persistent object of class TKunde with id {…} The object is already in persistent context.”
Of course I understand this, because in fact it is already existent.
But how to update an object without reading it before. Yes of course I could transfer the values field by field but I think there must be an easier way, right?
You can just use SaveOrUpdate method, that's what it does, if the id is null, it saves, otherwise, updates.
Why are you trying to retrieve the object from database to decide that, if you said it only needs a null check?
On the other hand, if you are receiving not-null id no matter what and it might have a chance that such id is not in database and you need to check it in advance, you can use Merge method instead. It does all of that automatically for you. Please refer to Merge method documentation (http://www.tmssoftware.biz/business/aurelius/doc/web/merging_objects.htm) for detailed explanation.
In the database this entry with the id in uid does exists!
I still get this error:
Cannot turn persistent object of class TKunde with id {5A5EAB78-926C-4961-9FEB-2E9113F0CA04}. The object is already in persistent context.
The second way I tried as you supposed with the .Merge function.
That works without an error, but all fields I don’t send in JSON are set to null in the database, that not
The only workaround I found is to retrieve the data manually by an TADOQuery and then copy all into a Superobject and merge it manually, but this is unlikely of course.
And this should not be if I understand you correct, it should automatically know if its an update or insert, right?
SaveOrUpdate doesn't work in this case because it will try to update (because it has an ID) but you want to insert.
Merge is the option, and the fact fields not present in JSON are null is expected, you are creating a new object, how do you expect Aurelius will know what are the fields returned by JSON and what are not?
Indeed in this case you must load the object using Aurelius and the properties of that object that you want to be changed.
Claim is different. It says that there is already another instance of a TKunde object with id=1 in the object manager. You can't have two or more instances of same entity (same id) in the manager, otherwise it can't control entity state.
That's why you should use Merge, or check if an object already exists and discard it.