Summary#
ui-page-query-without-a-take is a CONSIDER finding: a page holds a read of every row of an entity and uses it for
something other than drawing a list, a choice or a chart — a count, a total, a row handed to another component. A page
query is sent about 2 MB of rows an answer (How many rows a page is sent), so a count taken from the list stops where the
answer does.
When the page needs a number, ask for the number; it is answered over every row:
entity Visit {
DateTime At;
security { allow read, create when IsAnonymous || IsAuthenticated; }
}
[Route("/visits")] [Render(CSR)] [AllowAnonymous]
component VisitsPage() {
live var visits = Visit.Count();
render { Text($"{visits} visits"); }
}Signature#
live var n = Entity.Count(x => …); // a number over every row
live var rows = Entity.….Take(n).ToList(); // or a bound the author choseDescription#
When does it fire?#
On a component field read from an entity with no Take that the render reads, when none of the three specific rules
applies — it is not a list's rows (A list or table with no bound), not a choice's options
(A picker over every row — the SearchPicker) and not a chart's data (A chart over every row).
When is it silent?#
When the read is bounded (a Take, a one-row read, an aggregate, a child collection pinned to one parent), and when
the page never draws it at all — a read only an action uses, such as an export. An export of every row belongs in a
server function, which is never capped.
An editor's list#
A page that adds rows of the entity it lists before a Save is told here rather than by the list rule, because the list
rule's remedy — a Take — would hide the row just added: an unsaved row joins a list only while the list is every row
of its type. When the set is a handful by construction, say so on the member, with the reason:
entity Shelf {
[Required, MaxLength(40)] string Name;
int Rank;
security { allow read, create, update when IsAnonymous || IsAuthenticated; }
}
[Route("/shelves")] [Render(CSR)] [AllowAnonymous]
component ShelvesEditor() {
// Every shelf: one added here is on the list before Save only while the list is every row. A shop has a handful.
[SuppressWarning("ui-page-query-without-a-take")]
live var shelves = Shelf.OrderBy(s => s.Rank).ToList();
action Add() { UnitOfWork.Mark("Add a shelf"); new Shelf { Name = "New shelf", Rank = shelves.Count + 1 }; }
action Save() { UnitOfWork.Commit(); }
render {
Stack(gap: 2) {
foreach (var s in shelves) { Text(s.Name); }
Button("Add a shelf", onPress: Add);
Button("Save", onPress: Save);
}
}
}When it can grow, edit it a parent at a time — a parent's collection takes a new child too — or commit each row as it
is made and bound the list with .OrderBy(…).Take(n).
Why CONSIDER?#
Because it is the widest net: the linter sees that the page holds a read with no bound, not what the page does with it.
A component that pages its own rows still holds an unbounded read, and the remedy — a Take, a Where — is cheap.
See also#
- How many rows a page is sent — what a page is sent
- A list or table with no bound — a list's rows with no bound