From 9093c1407bb414ac6a2fdddd9b4b6065e0901a90 Mon Sep 17 00:00:00 2001 From: Stefan Sosic <59221826+StefanSosic@users.noreply.github.com> Date: Mon, 12 May 2025 20:57:08 +0200 Subject: [PATCH 1/5] Add documentation for SetAutoCalcFields method --- .../BestPractices/SetAutoCalcFields/index.md | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 content/docs/BestPractices/SetAutoCalcFields/index.md diff --git a/content/docs/BestPractices/SetAutoCalcFields/index.md b/content/docs/BestPractices/SetAutoCalcFields/index.md new file mode 100644 index 00000000..b98d9475 --- /dev/null +++ b/content/docs/BestPractices/SetAutoCalcFields/index.md @@ -0,0 +1,64 @@ +--- +title: "SetAutoCalcFields" +tags: ["AL","Performance"] +categories: ["Best Practice"] +--- + +In Business Central, `SetAutoCalcFields` is an essential method for optimizing the retrieval of calculated fields, such as FlowFields. Without `SetAutoCalcFields`, FlowFields require explicit calculation via `CalcFields`, which adds performance overhead. By automatically computing FlowFields upon retrieval, `SetAutoCalcFields` reduces unnecessary calls and improves efficiency when reading FlowFields from multiple records in a loop. + +See the documentation on learn.microsoft.com for more information about [SetAutoCalcFields](https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/methods-auto/record/record-setautocalcfields-method). + +{{% alert title="Note" color="info" %}} +Starting in Business Central 2025 release wave 1, the SetAutoCalcFields is also available on the RecordRef data type. +{{% /alert %}} + +## Why Use SetAutoCalcFields? + +Using `SetAutoCalcFields` ensures that FlowFields are computed automatically when retrieving a record, eliminating the need for additional `CalcFields` calls for each record. + +## General Guidelines for SetAutoCalcFields + +- Use `SetAutoCalcFields` before retrieving records (`FindSet`, `Find('-')`, etc.) when FlowFields need to be accessed. +- Avoid redundant `CalcFields` calls if `SetAutoCalcFields` has already been used. + + +## Examples +### Bad Code + +```AL +Customer.SetFilter(Balance, '>%1' , LargeCredit); +if Customer.FindSet() then + repeat + Customer.CalcFields(Balance); + if Customer.Balance > MaxCreditLimit then begin + Customer.Blocked := true; + Customer.Modify(); + end else + if Customer.Balance > LargeCredit then begin + Customer.Caution := true; + Customer.Modify(); + end; + until Customer.Next() = 0; +``` + +In this example, an extra call to `CalcFields` still must be issued for the code to be able to check the value of `Customer.Balance`. You can optimize this further by using the new `SetAutoCalcFields` method. + +### Good code + +```AL +Customer.SetFilter(Balance, '>%1', LargeCredit); +Customer.SetAutoCalcFields(Balance) +if Customer.FindSet() then + repeat + if Customer.Balance > MaxCreditLimit then begin + Customer.Blocked := true; + Customer.Modify(); + end else + if Customer.Balance > LargeCredit then begin + Customer.Caution := true; + Customer.Modify(); + end; + until Customer.Next() = 0; +``` + + From 77fa3d8f7fad2b5ac8f23722aa1301ed6ead388a Mon Sep 17 00:00:00 2001 From: Stefan Sosic <59221826+StefanSosic@users.noreply.github.com> Date: Thu, 29 May 2025 22:49:58 +0200 Subject: [PATCH 2/5] PR Suggestion Addition --- content/docs/BestPractices/SetAutoCalcFields/index.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/content/docs/BestPractices/SetAutoCalcFields/index.md b/content/docs/BestPractices/SetAutoCalcFields/index.md index b98d9475..80aa56e8 100644 --- a/content/docs/BestPractices/SetAutoCalcFields/index.md +++ b/content/docs/BestPractices/SetAutoCalcFields/index.md @@ -21,6 +21,12 @@ Using `SetAutoCalcFields` ensures that FlowFields are computed automatically whe - Use `SetAutoCalcFields` before retrieving records (`FindSet`, `Find('-')`, etc.) when FlowFields need to be accessed. - Avoid redundant `CalcFields` calls if `SetAutoCalcFields` has already been used. +## SetAutoCalcFields on List Pages +SetAutoCalcFields can be utilized in the OnOpenPage trigger to ensure specific FlowFields are pre-calculated before the user interacts with the page. This is particularly beneficial for list pages where calculations are necessary but not included in the visible fields. However, it's important to note that any FlowField already displayed on the page will be calculated automatically, making SetAutoCalcFields unnecessary for those fields. + +## SetAutoCalcFields or CalcFields +It's best practice to use SetAutoCalcFields when fetching a record since it ensures automatic FlowField calculation. On the other hand, CalcFields should only be used if you already have the record and need to explicitly trigger the calculation. This distinction prevents unnecessary performance overhead, ensuring that database queries remain optimized. + ## Examples ### Bad Code From d39e29c9fabc3efdc50e11f82ddaeee39c5abb4d Mon Sep 17 00:00:00 2001 From: Stefan Sosic <59221826+StefanSosic@users.noreply.github.com> Date: Wed, 4 Jun 2025 00:02:06 +0200 Subject: [PATCH 3/5] todo --- content/docs/BestPractices/if-not-insert-then-modify/index.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 content/docs/BestPractices/if-not-insert-then-modify/index.md diff --git a/content/docs/BestPractices/if-not-insert-then-modify/index.md b/content/docs/BestPractices/if-not-insert-then-modify/index.md new file mode 100644 index 00000000..8371f3a2 --- /dev/null +++ b/content/docs/BestPractices/if-not-insert-then-modify/index.md @@ -0,0 +1 @@ +//todo \ No newline at end of file From 0e30934d6f5a0f074789f0c60467d65cbcc7aa63 Mon Sep 17 00:00:00 2001 From: Stefan Sosic <59221826+StefanSosic@users.noreply.github.com> Date: Wed, 4 Jun 2025 00:18:38 +0200 Subject: [PATCH 4/5] Add ocumentation on 'if not Insert then Modify' best practices --- .../if-not-insert-then-modify/index.md | 56 ++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/content/docs/BestPractices/if-not-insert-then-modify/index.md b/content/docs/BestPractices/if-not-insert-then-modify/index.md index 8371f3a2..8792bc24 100644 --- a/content/docs/BestPractices/if-not-insert-then-modify/index.md +++ b/content/docs/BestPractices/if-not-insert-then-modify/index.md @@ -1 +1,55 @@ -//todo \ No newline at end of file +--- +title: "if not Insert then Modify" +tags: ["AL","Performance"] +categories: ["Best Practice"] +--- + +_Created by SosicStefan, Described by SosicStefan_ + +## Introduction + +When handling data insertion in Business Central, a common but inefficient pattern is attempting to insert a record and modifying it if the insert fails due to duplicate keys. This approach introduces unnecessary performance overhead and should be avoided. + +{{% alert title="Note" color="info" %}} +This pattern is only good when used on singleton table. Read more about [Singleton Table](https://alguidelines.dev/docs/navpatterns/patterns/singleton/singleton-table/). +{{% /alert %}} + +## Why Not Use 'If Not Insert Then Modify'? + +Using the following structure: + +```al +InitializeRecord(SomeRecord); +if not SomeRecord.Insert() then + SomeRecord.Modify(); +``` + +Presents several issues: + +- Prevents buffered inserts: This impacts performance as batch insert optimizations are lost. +- Generates unnecessary SQL errors: If a duplicate primary key exists, the failed insert raises an error, which Business Central must handle. +- Slower and less efficient: Handling SQL errors is far from an optimal way to check for record existence. + + +## Best Practice: Use IsEmpty + +Instead of relying on insert failures, ensure the record’s uniqueness upfront using a number series or an incremental primary key. If the data comes from an external source where duplicates might exist, use IsEmpty to check for existence. + +```AL +InitializeRecord(SomeRecord); +SomeRecord.SetRecFilter(); + +if SomeRecord.IsEmpty() then + SomeRecord.Insert() +else + SomeRecord.Modify(); +``` + +## Why IsEmpty is Better + +- No SQL errors: The check is done before attempting an insert. +- Performance improvement: Avoids unnecessary error handling and maintains buffered inserts. +- More readable and efficient: The intent is clear—checking existence before performing actions. + +## Summary +Avoid using if not Insert then Modify. Instead, ensure record uniqueness upfront or use IsEmpty to check existence efficiently. This leads to better performance and cleaner code. \ No newline at end of file From d81ad040904cf896d0094f25e881755b99f2e715 Mon Sep 17 00:00:00 2001 From: Stefan Sosic <59221826+StefanSosic@users.noreply.github.com> Date: Wed, 4 Jun 2025 00:20:02 +0200 Subject: [PATCH 5/5] remove --- .../BestPractices/SetAutoCalcFields/index.md | 70 ------------------- 1 file changed, 70 deletions(-) delete mode 100644 content/docs/BestPractices/SetAutoCalcFields/index.md diff --git a/content/docs/BestPractices/SetAutoCalcFields/index.md b/content/docs/BestPractices/SetAutoCalcFields/index.md deleted file mode 100644 index 80aa56e8..00000000 --- a/content/docs/BestPractices/SetAutoCalcFields/index.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -title: "SetAutoCalcFields" -tags: ["AL","Performance"] -categories: ["Best Practice"] ---- - -In Business Central, `SetAutoCalcFields` is an essential method for optimizing the retrieval of calculated fields, such as FlowFields. Without `SetAutoCalcFields`, FlowFields require explicit calculation via `CalcFields`, which adds performance overhead. By automatically computing FlowFields upon retrieval, `SetAutoCalcFields` reduces unnecessary calls and improves efficiency when reading FlowFields from multiple records in a loop. - -See the documentation on learn.microsoft.com for more information about [SetAutoCalcFields](https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/methods-auto/record/record-setautocalcfields-method). - -{{% alert title="Note" color="info" %}} -Starting in Business Central 2025 release wave 1, the SetAutoCalcFields is also available on the RecordRef data type. -{{% /alert %}} - -## Why Use SetAutoCalcFields? - -Using `SetAutoCalcFields` ensures that FlowFields are computed automatically when retrieving a record, eliminating the need for additional `CalcFields` calls for each record. - -## General Guidelines for SetAutoCalcFields - -- Use `SetAutoCalcFields` before retrieving records (`FindSet`, `Find('-')`, etc.) when FlowFields need to be accessed. -- Avoid redundant `CalcFields` calls if `SetAutoCalcFields` has already been used. - -## SetAutoCalcFields on List Pages -SetAutoCalcFields can be utilized in the OnOpenPage trigger to ensure specific FlowFields are pre-calculated before the user interacts with the page. This is particularly beneficial for list pages where calculations are necessary but not included in the visible fields. However, it's important to note that any FlowField already displayed on the page will be calculated automatically, making SetAutoCalcFields unnecessary for those fields. - -## SetAutoCalcFields or CalcFields -It's best practice to use SetAutoCalcFields when fetching a record since it ensures automatic FlowField calculation. On the other hand, CalcFields should only be used if you already have the record and need to explicitly trigger the calculation. This distinction prevents unnecessary performance overhead, ensuring that database queries remain optimized. - - -## Examples -### Bad Code - -```AL -Customer.SetFilter(Balance, '>%1' , LargeCredit); -if Customer.FindSet() then - repeat - Customer.CalcFields(Balance); - if Customer.Balance > MaxCreditLimit then begin - Customer.Blocked := true; - Customer.Modify(); - end else - if Customer.Balance > LargeCredit then begin - Customer.Caution := true; - Customer.Modify(); - end; - until Customer.Next() = 0; -``` - -In this example, an extra call to `CalcFields` still must be issued for the code to be able to check the value of `Customer.Balance`. You can optimize this further by using the new `SetAutoCalcFields` method. - -### Good code - -```AL -Customer.SetFilter(Balance, '>%1', LargeCredit); -Customer.SetAutoCalcFields(Balance) -if Customer.FindSet() then - repeat - if Customer.Balance > MaxCreditLimit then begin - Customer.Blocked := true; - Customer.Modify(); - end else - if Customer.Balance > LargeCredit then begin - Customer.Caution := true; - Customer.Modify(); - end; - until Customer.Next() = 0; -``` - -