Hello. I designed the following table in the datamodeler
UserGUID: TGuid; // ** primary key field
StorageVersion: Integer;
UserData: TBlob;
When the model gets generated, Datamodeler always emits
[Id('FUserGUID', TIdGenerator.Guid)]
atribute for the primary key field. This causes an error when POSTing
the corresponding entity with all fields prefilled by the client:
'Cannot save object of class . The object already has an id, use merge instead.'
The cause of this error is the check in the Objectmanager code:
if FObjects.HasIdValue(Entity) and not EntityType.SafeId.IsUserAssignedId then
raise ECannotSaveWithId.Create(Entity);
When posted, my object HAS UserGUID value prefilled and IsUserAssignedId function returns
false (it returns TRUE only when primary key contains more than one field or the generator
inherits from TIdGeneratorNone)
How do I force the DataModeler to emit TIdGeneratorNone for the UserGUID field?
I would hate to correct this manually in the generated unit. Is there a way to achieve this
directly in the model designer?
I'm sure @wlandgraf will have a better way ...
Meanwhile, you could try this:
procedure OnClassGenerated(Args: TClassGeneratedArgs);
var
LAttribute : TCodeAttributeDeclaration;
i : Integer;
LType : string;
begin
LType := LowerCase(Args.CodeType.Name);
if (LType = 't_your_type_to_force_lowercase') then begin
for i := 0 to Args.CodeType.CustomAttributes.Count - 1 do
begin
LAttribute := Args.CodeType.CustomAttributes.Items[i];
if (LAttribute.Name = 'Id') and (LAttribute.Arguments.Count > 1) then
begin
TCodeSnippetExpression(LAttribute.Arguments.Items[1].Value).Value := 'TIdGenerator.None';
end;
end;
end;
end;
Replace 't_your_type_to_force_lowercase' by your entity name in lowercase, like 'tuser' .
Thank you both for the solution. The script code works nice and for now this solves my problem.
BTW, is there any reason for raising the exception when an Id field with a generator already has a value when POSTed? One would think that in this case the generator could be simply ignored.
The presence or absence of an ID is key for Aurelius to know if a new ID should be generated, and if it should insert an new record or try to update an existing one.
Thank you for the reply, Wagner. It should insert new record because the method was POST, and the ID is already there so why to generate another one. The only scenario I could think of where the existing ID in POST could be a problem is that it could somehow confuse the ID generator sequence. But I asked just because I was curious. I accept this behavior as a fact, and because it should not cause any problem in my project, I consider the issue solved. Thanks again for your help.