Skip to content

Read audit names in one query per record type - #1000

Merged
KrzysztofPajak merged 1 commit into
developfrom
feature/audit-performance
Oct 30, 2026
Merged

KrzysztofPajak merged 1 commit into
developfrom
feature/audit-performance

Conversation

@KrzysztofPajak

Copy link
Copy Markdown
Member

Type: improvement

Issue

Follow-up to #999. Every staff save ends with the audit flush, and the request waits for it. To show "name (id)" instead of a bare id, the flush named every referenced record with its own query, one after another (AuditReferences.Describe, NameElements, LinkOwner). A change touching many list elements - a product with dozens of categories, specification attributes or tier prices, a copied product, an import - paid one database round trip per referenced record before the response went out.

Inserted records were also read back from the database at the flush, although the inserted entity is the stored state.

Storefront traffic is not affected either way: the tracker is active only for staff requests.

Solution

  • Names read in one query per record type. AuditReferences.Prefetch walks all entries of the flush first and only notes the records they need; they are then read with one $in query per record type and field (IAuditRecordReader.ReadMany, only the name/store field projected). Describing the entries afterwards reads nothing. A record seen by several entries is read once per flush (before: cached per name, not per record).
  • If the batched read fails, the names are read one by one as before; a name that cannot be found still leaves the id, never the change out.
  • Inserts keep their after state. RepositoryAudit.Inserted hands the inserted entity to the tracker (as a full update already does), so the flush no longer reads inserted records back.
  • LiteDB has no round trip to save, so its ReadMany reads the records one by one.

Breaking changes

  • IAuditRecordReader has a new member ReadMany (its implementations are MongoAuditRecordReader and LiteDBAuditRecordReader). AuditReferences gets Prefetch and DescribeEntry. Nothing stored changes.

Testing

  1. Unit tests: Grand.Infrastructure.Tests 279 and the audit tests of Grand.Web.Admin.Tests pass, with new tests for one read per record type (names, element names and owner stores), the fallback when the batched read fails, an insert not read back, and the LiteDB ReadMany.
  2. MongoAuditRecordReader.ReadMany checked against a local MongoDB: by id, by a numeric key (OrderStatus.StatusId), only the requested field projected, missing ids left out.
  3. Edit a product with several categories and specification attributes, change their display order: the Change history shows the same names as before.
  4. Add a note to a merchandise return: it shows in the return's history and under the return's store, as before.

The end-of-request flush named every referenced record with its own query, one after another, while the staff member waited: a product with dozens of categories, attributes or tier prices took dozens of round trips. The references are now collected for all entries of the flush first and read with one $in query per record type (IAuditRecordReader.ReadMany); describing the entries then reads nothing. Inserted records keep the entity as their after state instead of being read back at the flush.
Copilot AI balanced review requested due to automatic review settings October 30, 2026 14:49

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

Comment on lines +31 to +33
foreach (var value in values.Distinct())
if (await Read(entityType, value, key, field) is { } record)
records[value] = record;
Comment on lines +53 to +56
catch (Exception)
{
//fails again when described
}
Comment on lines +71 to +74
catch (Exception)
{
//read one by one when described
}
Comment on lines +311 to +314
catch (Exception)
{
entry = null;
}
@KrzysztofPajak
KrzysztofPajak merged commit ba4fc71 into develop Oct 30, 2026
9 checks passed
@KrzysztofPajak
KrzysztofPajak deleted the feature/audit-performance branch October 30, 2026 15:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants