Summary#
ui-unbounded-list-does-not-page is a SHOULD finding: a page draws a list from a read of every row of an
entity, and nothing on the page pages it. A page query is sent about 2 MB of rows an answer (How many rows a page is sent) —
about a thousand whole rows of a wide entity, several thousand of a narrow one — so once the table passes that the list
stops where the answer does — and nothing on the page says so. The finding quotes the number for your entity.
Page it — LoadMoreButton(rows) under the list offers the rest (Lists that load more):
[Route("/jobs/all")] [Render(CSR)] [AllowAnonymous]
component AllJobsPage() {
live var jobs = Job.OrderByDescending(j => j.PostedAt).ToList();
render {
Stack(gap: 2, p: 6) {
foreach (var j in jobs) { Text(j.Title); }
LoadMoreButton(jobs);
}
}
}…or write the bound the page means:
entity Job {
[Required, MaxLength(120)] string Title;
DateTime PostedAt;
bool Filled = false;
security { allow read, create, update when IsAnonymous || IsAuthenticated; }
}
[Route("/jobs")] [Render(CSR)] [AllowAnonymous]
component JobsPage() {
string search = "";
live var jobs = Job.Where(j => !j.Filled && j.Title.Contains(search))
.OrderByDescending(j => j.PostedAt).Take(50).ToList();
render {
Stack(gap: 2, p: 6) {
SearchField("Search jobs", value: search);
foreach (var j in jobs) { Text(j.Title); }
}
}
}Signature#
live var rows = Entity.Where(…).OrderBy(x => …).Take(n).ToList(); // what the rule asks for
live var rows = Entity.ToList(); // what it flags, when drawn as a listDescription#
When does it fire?#
On a component field whose read is rooted at an entity, has no Take, and is drawn as a list: the source of a
foreach in the render, or a table control's rows. A member derived from it counts as the read itself, so
var shown = rows.Where(…) drawn in a foreach (or a DataGrid) is found through shown — a list computed from the
read is not a window of anything, so nothing can page it.
When is it silent?#
When the page pages the read: it is drawn by a DataGrid or under a LoadMoreButton, which offer the rows past
the first answer by themselves, or the component asks it .HasMore / .LoadMore() itself (Lists that load more). Or when
the read is bounded by what the author wrote: a Take; a one-row read (First, Single, a filter on the id or
on a [Unique] column) or a few named keys (p.Slug == a || p.Slug == b, slugs.Contains(p.Slug)); an aggregate
(Count, Sum, a GroupBy); or a child collection — a filter pinning a reference to one parent
(Line.Where(l => l.Order == order), through a reference the row inherits too), to the parents the page already
holds (shownIds.Contains(l.Order.Id)), or a parent's collection (order.Lines). A chart, a map or a dropdown over
the read reports the more specific rule instead (A chart over every row, A picker over every row — the SearchPicker).
What about an editor?#
A page that adds rows of the entity it lists — new Tier { … } in an action, or in a method of the component's own,
saved later — is an editor, and for an editor a Take is the wrong advice: an unsaved row joins a list only while the
list is every row of its type, so a windowed list would hide the row just added until Save. Such a list is reported by
A page query with no bound at its CONSIDER tier instead, with the editor's choices: say that the set is a handful by
construction, 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.
What can it not tell?#
Whether the table can grow. A list of a few dozen reference rows is flagged too; a .Take(n) naming its size says
what the page means and costs nothing. Nor how many children a parent has: a pinned read is trusted as bounded. Nor
whether an editor's row is made in a server function the page calls — that row is saved where it is made, so the
page's list takes it from its re-read, and the advice for a list stands.
Why SHOULD and not MUST?#
Because the page works — for the rows the first answer holds. The finding is a list that quietly stops being complete as the data grows, which a pre-ship gate should not fail on, and which an author should fix before the data gets there.
See also#
- How many rows a page is sent — what a page is sent, and what is never capped
- A page query with no bound — the catch-all for any other unbounded page query