Six carried-over threads: - api-page-least-privilege-write-access fixtures: added the mandatory EntityName/EntitySetName properties (AL0485). - pages-must-not-contain-business-logic fixtures: Sales Line has no "Total Amount" field; replaced with the real "Line Amount" (field 103). - test-feature-scenario-tags.good.al and test-one-when-per-test.good.al: CreatePriceHeader leaves a price list in Draft status, which price calculation ignores. Added Validate(Status, Active) + Modify before the sales line that depends on it. Verified Status field/enum against PriceListHeader.Table.al and PriceStatus.Enum.al in the BCApps clone. - exposed-objects-must-be-in-a-permission-set.md: a published codeunit is a SOAP endpoint (SOAP is deprecated), not OData - Page/Query are the OData object types. Corrected and pointed new integrations at API pages/queries instead. - al-error-handling-review.md: the log-writes-must-survive-rollback cue selected on Session.StartSession, which only appears in the compliant fix, never in the anti-pattern - the bad fixture could never be worklisted. Recued on the actual risk shape (log insert around a failed TryFunction/GetLastError* path, then raise/propagate), with StartSession as an explicit compliant discriminator instead. - page-design-must-match-bc-page-type-conventions.md: the enum value is NavigatePage, not Navigate; noted the type list is a selected subset, not an exhaustive PageType catalogue (PromptDialog, ConfigurationDialog, UserControlHost, XmlPort also exist, out of this article's scope). Four new correctness gaps: - release-must-update-app-version.md: "the version is the only identity" was backwards - id is the app's stable identity, version identifies a release/code-state of it. - defensive-vs-offensive-code-must-match-blast-radius.good.al: the "low blast radius" example had no else branch, so a failed Customer.Get() left the field at its prior/default value instead of the explicit chosen fallback the article claims to demonstrate. Added the else. - bcpt-scenarios-must-be-app-specific.good.al: InitTest and both measured StartScenario/EndScenario sections were empty/comment-only, so the "app-specific" fixture measured no actual work. Filled in a real, self-contained header+line creation path. - upgrade-tag-logic-must-not-nest-deeply.good.al: the flattened version dropped both safety conditions the bad fixture had (Discount % = 0, nonblank posting group), silently changing behavior instead of just removing nesting. Extracted the guarded update into a helper with both conditions preserved as early exits. Also converted this PR's remaining plain-backtick "See sample:" sample references (16 articles) to the READ-convention markdown-link form, matching the fix already made on #156/#158. Rebased onto upstream/main (conflicts in al-ui-review.md, al-style-review.md, al-upgrade-review.md against merged upstream PRs - all additive, both sides' worklist cues retained).
2.1 KiB
| bc-version | domain | keywords | technologies | countries | application-area | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
data-modeling |
|
|
|
|
Pictures must be stored in a Media/MediaSet field, not BLOB
Description
BLOB is still a valid AL field type for arbitrary binary data, but it is
not the right choice for storing pictures or images. The current
recommendation is the Media field type for a single image, or
MediaSet when a record needs several independent images (e.g. multiple
product photos) — MediaSet is a collection of separately-imported media
objects, each with its own identity; it does not generate resized variants
or thumbnails on its own, and displaying more than one item still requires
custom page handling. Media/MediaSet integrate with the platform's
picture control and media repository, which a plain BLOB field does not
— but any derived preview or thumbnail image still has to be generated
explicitly and stored in its own field, regardless of which type holds the
source image.
BLOB remains the correct choice for genuinely arbitrary binary payloads
that are not images and don't benefit from the media pipeline (e.g. a raw
file attachment blob unrelated to picture rendering).
Best Practice
Use Media for a single image, or MediaSet for multiple independent
images, for any field that holds a picture.
See sample: pictures-must-use-media-not-blob.good.al.
Anti Pattern
A BLOB field named "Picture" compiles and stores the image bytes, but
it misses the picture control integration and media repository that a
Media/MediaSet field provides for free — the anti pattern is choosing
BLOB for image storage out of habit rather than recognizing that the
field is holding a picture, not generic binary data. A related anti
pattern: assuming MediaSet gives automatic image variants or thumbnails
because it sounds like a collection with derived versions — it is only a
collection of independently-imported media objects.
See sample: pictures-must-use-media-not-blob.bad.al.