mirror of
https://github.com/microsoft/BCQuality.git
synced 2026-10-05 06:36:55 +01:00
Add query filter semantics guidance (#186)
Some checks are pending
Validate knowledge index / validate-index (push) Waiting to run
Validate AL review fixtures / validate-review-fixtures (push) Waiting to run
Validate skill index and report schemas / validate-contract (push) Waiting to run
Validate frontmatter and structure / validate (push) Waiting to run
Some checks are pending
Validate knowledge index / validate-index (push) Waiting to run
Validate AL review fixtures / validate-review-fixtures (push) Waiting to run
Validate skill index and report schemas / validate-contract (push) Waiting to run
Validate frontmatter and structure / validate (push) Waiting to run
This commit is contained in:
parent
b7617fb48a
commit
861f53dd97
8 changed files with 225 additions and 3 deletions
|
|
@ -0,0 +1,39 @@
|
|||
query 50428 "Static Query Filter Bad"
|
||||
{
|
||||
QueryType = Normal;
|
||||
|
||||
elements
|
||||
{
|
||||
dataitem(SalesHeader; "Sales Header")
|
||||
{
|
||||
DataItemTableFilter = Status = const(Open);
|
||||
|
||||
column(DocumentNo; "No.")
|
||||
{
|
||||
}
|
||||
filter(StatusFilter; Status)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
codeunit 50429 "Static Query Filter Bad"
|
||||
{
|
||||
procedure ReadReleasedOrders()
|
||||
var
|
||||
SalesHeader: Record "Sales Header";
|
||||
SalesHeaderQuery: Query "Static Query Filter Bad";
|
||||
begin
|
||||
// This is combined with Status = Open and returns no rows.
|
||||
SalesHeaderQuery.SetRange(StatusFilter, SalesHeader.Status::Released);
|
||||
SalesHeaderQuery.Open();
|
||||
while SalesHeaderQuery.Read() do
|
||||
ProcessOrder(SalesHeaderQuery.DocumentNo);
|
||||
SalesHeaderQuery.Close();
|
||||
end;
|
||||
|
||||
local procedure ProcessOrder(DocumentNo: Code[20])
|
||||
begin
|
||||
end;
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
query 50430 "Static Query Filter Good"
|
||||
{
|
||||
QueryType = Normal;
|
||||
|
||||
elements
|
||||
{
|
||||
dataitem(SalesHeader; "Sales Header")
|
||||
{
|
||||
DataItemTableFilter = "Document Type" = const(Order);
|
||||
|
||||
column(DocumentNo; "No.")
|
||||
{
|
||||
}
|
||||
filter(StatusFilter; Status)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
codeunit 50431 "Static Query Filter Good"
|
||||
{
|
||||
procedure ReadReleasedOrders()
|
||||
var
|
||||
SalesHeader: Record "Sales Header";
|
||||
SalesHeaderQuery: Query "Static Query Filter Good";
|
||||
begin
|
||||
SalesHeaderQuery.SetRange(StatusFilter, SalesHeader.Status::Released);
|
||||
SalesHeaderQuery.Open();
|
||||
while SalesHeaderQuery.Read() do
|
||||
ProcessOrder(SalesHeaderQuery.DocumentNo);
|
||||
SalesHeaderQuery.Close();
|
||||
end;
|
||||
|
||||
local procedure ProcessOrder(DocumentNo: Code[20])
|
||||
begin
|
||||
end;
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
---
|
||||
bc-version: [all]
|
||||
domain: query
|
||||
keywords: [query, dataitemtablefilter, setfilter, setrange, static-filter, filter-precedence]
|
||||
technologies: [al]
|
||||
countries: [w1]
|
||||
application-area: [all]
|
||||
---
|
||||
|
||||
# DataItemTableFilter cannot be overwritten at runtime
|
||||
|
||||
## Description
|
||||
|
||||
`DataItemTableFilter` defines a static filter on a Query dataitem. A runtime `SetFilter` or `SetRange` on the same source field does not replace that filter. The static and runtime filters are combined with AND, so contradictory values produce an empty dataset instead of broadening or replacing the query definition.
|
||||
|
||||
## Best Practice
|
||||
|
||||
Keep only invariant restrictions in `DataItemTableFilter`. Expose caller-selectable fields through a column or filter row and apply their values with `SetFilter` or `SetRange` before `Open()`. When both filter types intentionally target the same field, ensure their intersection represents the required dataset.
|
||||
|
||||
See sample: [`dataitemtablefilter-cannot-be-overwritten-at-runtime.good.al`](dataitemtablefilter-cannot-be-overwritten-at-runtime.good.al).
|
||||
|
||||
## Anti Pattern
|
||||
|
||||
Define a static filter in `DataItemTableFilter`, then apply a contradictory runtime filter to the same source field while expecting the runtime filter to replace the static one. Both filters remain effective and the query returns no rows.
|
||||
|
||||
See sample: [`dataitemtablefilter-cannot-be-overwritten-at-runtime.bad.al`](dataitemtablefilter-cannot-be-overwritten-at-runtime.bad.al).
|
||||
|
||||
## References
|
||||
|
||||
Filtering in Query objects — https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-query-filters
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
query 50432 "Column Query Filter Bad"
|
||||
{
|
||||
QueryType = Normal;
|
||||
|
||||
elements
|
||||
{
|
||||
dataitem(SalesLine; "Sales Line")
|
||||
{
|
||||
column(DocumentNo; "Document No.")
|
||||
{
|
||||
}
|
||||
column(LineQuantity; Quantity)
|
||||
{
|
||||
ColumnFilter = LineQuantity = filter(> 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
codeunit 50433 "Column Query Filter Bad"
|
||||
{
|
||||
procedure ReadSmallPositiveLines()
|
||||
var
|
||||
SalesLineQuery: Query "Column Query Filter Bad";
|
||||
begin
|
||||
// This replaces > 0, so negative quantities are also returned.
|
||||
SalesLineQuery.SetFilter(LineQuantity, '<100');
|
||||
SalesLineQuery.Open();
|
||||
while SalesLineQuery.Read() do
|
||||
ProcessLine(SalesLineQuery.DocumentNo, SalesLineQuery.LineQuantity);
|
||||
SalesLineQuery.Close();
|
||||
end;
|
||||
|
||||
local procedure ProcessLine(DocumentNo: Code[20]; Quantity: Decimal)
|
||||
begin
|
||||
end;
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
query 50434 "Column Query Filter Good"
|
||||
{
|
||||
QueryType = Normal;
|
||||
|
||||
elements
|
||||
{
|
||||
dataitem(SalesLine; "Sales Line")
|
||||
{
|
||||
DataItemTableFilter = Quantity = filter(> 0);
|
||||
|
||||
column(DocumentNo; "Document No.")
|
||||
{
|
||||
}
|
||||
column(LineQuantity; Quantity)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
codeunit 50435 "Column Query Filter Good"
|
||||
{
|
||||
procedure ReadSmallPositiveLines()
|
||||
var
|
||||
SalesLineQuery: Query "Column Query Filter Good";
|
||||
begin
|
||||
// This combines with the invariant Quantity > 0 dataitem filter.
|
||||
SalesLineQuery.SetFilter(LineQuantity, '<100');
|
||||
SalesLineQuery.Open();
|
||||
while SalesLineQuery.Read() do
|
||||
ProcessLine(SalesLineQuery.DocumentNo, SalesLineQuery.LineQuantity);
|
||||
SalesLineQuery.Close();
|
||||
end;
|
||||
|
||||
local procedure ProcessLine(DocumentNo: Code[20]; Quantity: Decimal)
|
||||
begin
|
||||
end;
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
---
|
||||
bc-version: [all]
|
||||
domain: query
|
||||
keywords: [query, columnfilter, setfilter, setrange, filter-precedence, runtime-filter]
|
||||
technologies: [al]
|
||||
countries: [w1]
|
||||
application-area: [all]
|
||||
---
|
||||
|
||||
# SetFilter and SetRange overwrite Query ColumnFilter
|
||||
|
||||
## Description
|
||||
|
||||
`ColumnFilter` on a Query column or filter row defines a dynamic filter. A runtime `SetFilter` or `SetRange` on that same column or filter row replaces the `ColumnFilter`; it does not combine the two conditions. Rows excluded by the declarative filter can therefore reappear when the runtime filter omits that restriction.
|
||||
|
||||
## Best Practice
|
||||
|
||||
Place invariant restrictions in `DataItemTableFilter`, which runtime filters cannot overwrite. When a `ColumnFilter` is intentionally replaceable, make each runtime `SetFilter` or `SetRange` express the complete required condition before `Open()`.
|
||||
|
||||
See sample: [`setfilter-overwrites-query-columnfilter.good.al`](setfilter-overwrites-query-columnfilter.good.al).
|
||||
|
||||
## Anti Pattern
|
||||
|
||||
Apply `SetFilter` or `SetRange` to a column or filter row and rely on its existing `ColumnFilter` to remain effective. The runtime call replaces that filter and can admit rows that the query definition appeared to exclude.
|
||||
|
||||
See sample: [`setfilter-overwrites-query-columnfilter.bad.al`](setfilter-overwrites-query-columnfilter.bad.al).
|
||||
|
||||
## References
|
||||
|
||||
Filtering in Query objects — https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-query-filters
|
||||
Loading…
Add table
Add a link
Reference in a new issue