How to add additional records when an entity is being inserted?

I have a 1-many assosiation on TProjectTool -> TProjectToolModule.
What I would like to achive is that, when a TProjectTool is being inserted I'd like to manually add a TProjectToolModule as well.

I've dropped a TAureliusModelEvents component on my datamodule, and implemented the OnInserting event like this:

if Args.Entity is TProjectTool then begin
  ProjectToolInserting(TObjectManager(Args.Manager), TProjectTool(Args.Entity));

Then I have this procedure where I perform try to add the additional record in TProjectToolModule:

procedure TAppModelEvents.ProjectToolInserting(aManager: TObjectManager; aProjectTool: TProjectTool);
  lProjectToolModule: TProjectToolModule;
  lProjectToolModule := TProjectToolModule.Create;
  lProjectToolModule.ProjectToolID := aProjectTool;
  lProjectToolModule.Name := 'Some name';
  lProjectToolModule.SortNo := 0;
  //I've also tried aManager.Save(lProjectToolModule);

All the code runs just fine without any exceptions, but my additional record (TProjectToolModule) is not being inserted. Any hints or suggestions as to what I'm doing wrong here?

Here are some snippets of my entities:

  /* Snippet of ProjectTool entity
  [Id('FID', TIdGenerator.IdentityOrSequence)]
  TProjectTool = class
    [Column('ID', [TColumnProp.Required, TColumnProp.NoInsert, TColumnProp.NoUpdate])]
    FID: Integer;

    [Column('Name', [], 100)]
    FName: Nullable<string>;
  Snippet End */

  /* Snippet of ProjectToolModule
  [Id('FID', TIdGenerator.IdentityOrSequence)]
  TProjectToolModule = class
    [Column('ID', [TColumnProp.Required, TColumnProp.NoInsert, TColumnProp.NoUpdate])]
    FID: Integer;

    [Column('Name', [], 100)]
    FName: Nullable<string>;

    [Column('SortNo', [])]
    FSortNo: Nullable<Double>;

    [Association([TAssociationProp.Lazy, TAssociationProp.Required], CascadeTypeAll - [TCascadeType.Remove])]
    [JoinColumn('ProjectToolID', [TColumnProp.Required], 'ID')]
    FProjectToolID: Proxy<TProjectTool>;
  Snippet End */

The problem here is that OnInsert is a "low level" event, which is called when an INSERT SQL statement is execute. At this point, the manager is in the middle of a complex process of checking changes, dependencies, associations, cascades, etc.

So it's simply not safe to rely that changing the object structure in the middle of such project will make it work like it was changed at the beginning of the process.

One thing you can try to do is to create a second manager to insert the TProjectToolModule in the database, and then discard such manager. But then you have to be aware that the original TProjectTool won't have such object in its list and your code must take that into account for further work. So this solution will work only at "database level" (making sure the record is there, but the object structure is not reliable).

In this case, if you need the object structure to also be reliable, i.e., having a TProjectToolModule inside the list whenever you save a TProjectTool object, then I recommend you move such code to the level of your application. making sure whenever you save a TProjectTool, such list has a new object, before you call Manager.Save.

Ok, I see.
Just to make sure we are on the same page, the code I posted is from my server code, and (for me) considered a business rule.

Let me phrase my question a bit differently: If I have (what I consider to be a business rule) where when a particular entity is about to be created and inserted....I would like to insert a associated entity.
What would be the "best practice" to do such a thing?

Thank you.

Yes, the code you presented is your application. But it's an Aurelius event.
What I'm suggesting is that you "simply" do that outside Aurelius scope.

In summary, whenever you do


You also make sure to include the module:

if ProjectTool.Modules.Count = 0 then

Of course, the above is just pseudo-code, your real application would need a refactor so that you can centralize such code and make sure it's called whenever a project tool is created.

Thank you Wagner, and thank you for bearing with me.

Regarding your last reply, that sound interesting for sure. Please let me have some time to think about it and try to understand better how and what to do before I might elaborate further.

In then meantime I'll create a service doing the Post, and Route it to replace/hide the automatically generated xData/Aurelius Post.

Ok. Thank you.
But: if you are using XData and the POST endpoint is the central place for inserting it, then in this case you can use XData OnEntityInserting event.

That is a higher level event that is called before Manager.Save is called, and in this case, you can add the detail item in the master object, and it should work.