bcquality/microsoft/knowledge/events/changecompany-runs-triggers-in-the-calling-company.good.al
waldo1001 fc544f7bd5 knowledge(events): serialize the setup-counter increment; promote article and wire the review skill
PR #152 round 3 (JesperSchulz):
- The good sample's OnAfterInsertEvent subscriber still raced on the
  shared "Transfer Setup Good" singleton (Get/increment/Modify);
  AutoIncrement only protected the request key. Added
  TransferSetup.LockTable() before Get() to serialize concurrent
  background sessions.
- Promoted changecompany-runs-triggers-in-the-calling-company from
  community/knowledge/events/ to microsoft/knowledge/events/, and wired
  ChangeCompany/StartSession/RunTrigger tokens plus a targeted
  detection cue into microsoft/skills/review/al-events-review.md so a
  diff containing the anti-pattern reliably worklists this article,
  preserving the documented RunTrigger=false hand-off exception.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-15 11:21:52 +02:00

84 lines
2.4 KiB
AL

codeunit 50100 "Transfer Request Good"
{
// Self-contained demonstration of the best practice. Not derived from base-app source.
procedure RequestFromCompany(TargetCompany: Text[30]; ItemNo: Code[20]; Quantity: Decimal)
var
TransferRequest: Record "Transfer Request Good";
SessionId: Integer;
begin
TransferRequest.Init();
TransferRequest."Item No." := ItemNo;
TransferRequest.Quantity := Quantity;
// The insert runs inside TargetCompany, so OnInsert and the subscriber read that company's setup.
StartSession(SessionId, Codeunit::"Transfer Request Create Good", TargetCompany, TransferRequest);
end;
}
codeunit 50102 "Transfer Request Create Good"
{
TableNo = "Transfer Request Good";
trigger OnRun()
begin
// "Entry No." is AutoIncrement, so concurrent background sessions in TargetCompany never race on the same value.
Rec.Insert(true);
end;
}
table 50100 "Transfer Request Good"
{
DataClassification = CustomerContent;
fields
{
field(1; "Entry No."; Integer) { AutoIncrement = true; }
field(2; "Item No."; Code[20]) { }
field(3; Quantity; Decimal) { }
field(4; "Location Code"; Code[10]) { }
}
keys
{
key(PK; "Entry No.") { Clustered = true; }
}
trigger OnInsert()
var
TransferSetup: Record "Transfer Setup Good";
begin
TransferSetup.Get();
"Location Code" := TransferSetup."Default Location Code";
end;
}
table 50101 "Transfer Setup Good"
{
DataClassification = CustomerContent;
fields
{
field(1; "Primary Key"; Code[10]) { }
field(2; "Default Location Code"; Code[10]) { }
field(3; "Open Requests"; Integer) { }
}
keys
{
key(PK; "Primary Key") { Clustered = true; }
}
}
codeunit 50101 "Transfer Request Count Good"
{
[EventSubscriber(ObjectType::Table, Database::"Transfer Request Good", OnAfterInsertEvent, '', false, false)]
local procedure CountOpenRequest(var Rec: Record "Transfer Request Good"; RunTrigger: Boolean)
var
TransferSetup: Record "Transfer Setup Good";
begin
// Serializes the read-modify-write so concurrent background sessions don't lose an increment.
TransferSetup.LockTable();
TransferSetup.Get();
TransferSetup."Open Requests" += 1;
TransferSetup.Modify();
end;
}