Trial - boosting prospect grid loading performance
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
## Plan: Prospect list performance overhaul
|
||||
|
||||
The current bottleneck is not just data volume; it is the combination of loading every prospect and every nested interaction at once, then rendering all cards in the browser. In the current flow, each page loads the full list from `ProspectService.GetProspectsAsync`, includes all `Images` and `Interactions` plus each `User`, and then `ProspectGrid` renders every card through `Repeater` without virtualization. With hundreds of records, the UI does repeated LINQ work per card and hits a lot of DOM work in one render.
|
||||
|
||||
### Recommended approach
|
||||
Use a two-part fix: reduce the server-side payload and virtualize the client-side rendering. The best gains will come from paginating or virtualizing the list, then trimming unnecessary nested load and repeated per-row calculations.
|
||||
|
||||
### Steps
|
||||
1. Profile the bottleneck and cap the visible list size
|
||||
- Confirm the prospect pages are loading all records at once because `GetProspectsAsync` currently does `ToListAsync()` without paging or limit.
|
||||
- Add a page-size/virtualized flow so only the visible slice is fetched and rendered.
|
||||
- This change must happen in the page and service layer before any UI refactor.
|
||||
|
||||
2. Reduce EF payload in `ProspectService.GetProspectsAsync`
|
||||
- Update `FoodsharingSiegen.Server/Data/Service/ProspectService.cs` so it accepts pagination arguments (`skip`, `take`, optional filters) instead of returning the full unbounded list.
|
||||
- Keep the query as `AsNoTracking()` but avoid eager-loading all `Images` and every `User` for every prospect when the page only needs a summary view.
|
||||
- For the list pages, load only the subset needed for the grid and defer expensive image/user data until a detail action opens.
|
||||
- Filter and sort should happen server-side when possible to avoid moving hundreds of full entities into memory and then filtering again in the browser.
|
||||
|
||||
3. Replace the full list render with virtualization
|
||||
- Convert the repeated list in `FoodsharingSiegen.Server/Controls/ProspectGrid.razor` to a virtualized list or paged container, rather than rendering a full `<Repeater Items="@Prospects">` for all rows.
|
||||
- Keep the visible cards only; the hidden rows should not be in the DOM.
|
||||
- This removes the biggest DOM cost on pages with hundreds of entries.
|
||||
|
||||
4. Remove repeated per-row computation in the card components
|
||||
- In `FoodsharingSiegen.Server/Controls/InteractionRow.razor.cs`, the properties `Interactions`, `Done`, `Alert`, `NotNeeded` recalculate on every render from a list of nested items. With hundreds of cards this becomes expensive.
|
||||
- Replace repeated `Where()` chains with precomputed values from the loaded model or cached values at the prospect object level.
|
||||
- In `FoodsharingSiegen.Contracts/Entity/Prospect.cs`, avoid deriving `Complete` from `Interactions.Any()` on every render when a summary value is already known in the data model.
|
||||
- Keep the card logic free of repeated `ToList()` and `Any()` chains during render.
|
||||
|
||||
5. Tighten data shaping for each list page
|
||||
- The onboarding, verification, archive, and done pages all load the same full set of entities and then apply client-side filters with `ApplyFilter` and `ApplySort` in `FoodsharingSiegen.Shared/Helper/FilterHelper.cs`.
|
||||
- Move the expensive filtering/sorting to SQL or at least to the server-side query layer; reduce the list to a smaller result set before it reaches the UI.
|
||||
- Keep `ProspectList.ApplyFilter` only as a fallback for small local slices, not as the primary path for large lists.
|
||||
|
||||
6. Verify the improvement with focused checks
|
||||
- Measure page load time before and after with a realistic dataset of several hundred prospects.
|
||||
- Validate that the list stays responsive during scrolling and interaction changes.
|
||||
- Run the relevant .NET tests and render-check the prospect pages manually.
|
||||
|
||||
### Relevant files
|
||||
- `FoodsharingSiegen.Server/Data/Service/ProspectService.cs` — main query and database fetch point.
|
||||
- `FoodsharingSiegen.Server/Controls/ProspectGrid.razor` — full-list rendering path.
|
||||
- `FoodsharingSiegen.Server/Controls/ProspectContainer.razor` — per-card DOM and nested component rendering.
|
||||
- `FoodsharingSiegen.Server/Controls/InteractionRow.razor.cs` — repeated LINQ work in each row.
|
||||
- `FoodsharingSiegen.Contracts/Entity/Prospect.cs` — computed values that trigger repeated work.
|
||||
- `FoodsharingSiegen.Shared/Helper/FilterHelper.cs` — client-side list filtering/sorting on large sets.
|
||||
- `FoodsharingSiegen.Server/Pages/Prospects.razor`, `FoodsharingSiegen.Server/Pages/ProspectsAll.razor`, `FoodsharingSiegen.Server/Pages/ProspectsVerify.razor`, `FoodsharingSiegen.Server/Pages/ProspectsDone.razor` — list page orchestration and data flow.
|
||||
|
||||
### Key decision
|
||||
The highest-value fix is to stop returning and rendering all prospects at once. A virtualized/paged list with a trimmed query shape will provide the biggest speedup and should be the first implementation target.
|
||||
|
||||
### Optional follow-up improvements
|
||||
- Precompute a lightweight summary model for the grid instead of the full `Prospect` entity.
|
||||
- Add a server-side count query to support proper paging without loading every record.
|
||||
- Consider splitting the list into “summary” and “detail” data so the main dashboard never loads full nested relationship graphs by default.
|
||||
Reference in New Issue
Block a user