PL-400 cheat sheet
PL-400 · Keep the key ideas within reach.
Create a technical design
Unmanaged solutions are the editable source used in development; managed solutions are the locked artifacts deployed to test and production.
The publisher prefix is fixed at publisher creation and prepends every new schema name; it cannot be changed once components exist.
Use solution upgrade (stage, then apply upgrade) to delete components removed between versions; a plain update leaves them behind in the target.
Choose a virtual table when data must remain in an external system; choose standard or elastic tables when the data must be stored in Dataverse.
Elastic tables suit high-volume, partition-key-based, JSON-payload scenarios; standard tables suit relational transactional workloads.
Store connection references and environment variables inside the solution and supply environment-specific values through a deployment settings file at import.
Segment large solutions by functional area; resolve cross-solution dependencies by layering, never by circular references.
Cloud flows must be added as solution-aware components to travel with a solution; non-solution flows cannot be exported.
Business units define the data ownership boundary; security roles plus teams define access within and across those boundaries.
Configure Microsoft Dataverse
Privilege levels are User (own records), Business Unit, Parent:Child (business unit hierarchy), and Organization (all records).
Field-level security requires a Field Security Profile plus the table-level privilege; secured columns return null for users without the profile.
Auditing must be enabled at the environment, the table, and the column before a column value change is recorded.
Calculated columns evaluate when read, are not stored, and cannot reference calculated or rollup columns from another table.
Rollup columns aggregate related child records asynchronously; force a refresh with the CalculateRollupField message.
Cascade options are Cascade All, Cascade Active, Cascade User-Owned, Cascade None, Remove Link, and Restrict; Restrict blocks parent deletion.
A native many-to-many relationship creates its own intersect table; a manual N:N needs a custom intersect table with two lookups.
Alternate keys let integrations address records by business key and enable upsert; a table supports up to five alternate keys.
Business rules with scope Entity run server-side for every client and API call; form scope runs only in model-driven forms.
Create and configure Power Apps
Non-delegable queries stop at the data row limit (default 500, maximum 2000); delegable queries are translated and executed by the source.
Delegable functions include Filter, LookUp, Sort, and Sum where the source supports them; aggregation over a collected table is always local.
Set() creates a global variable; UpdateContext() creates a context variable scoped to the current screen.
App.Formulas named formulas recalculate automatically when dependencies change and reduce OnStart data load.
OnStart runs once per app launch; use it for navigation and parameter parsing rather than heavy data retrieval.
Model-driven navigation comes from the sitemap; visible tables and commands are filtered by the signed-in user's security roles.
The editable grid control allows inline editing of multiple records from a view without opening each record form.
Business process flows guide stage completion across tables; conditional stages control when a stage becomes active.
With() scopes intermediate values and Concurrent() runs independent calls in parallel to reduce round trips.
Extend the user experience
PCF components are field-bound (one column) or dataset-bound (a view); the manifest declares the type.
PCF lifecycle order is init, updateView, getOutputs, destroy; call notifyOutputChanged so the host reads the new value.
In model-driven forms obtain the form with executionContext.getFormContext() when the handler is registered to pass the execution context.
control.setNotification shows a field-level message; formContext.ui.setFormNotification shows a form-level banner.
addOnChange handlers fire for changes made through the form context; direct Web API updates do not trigger them.
Custom pages are canvas apps embedded in a model-driven app and read the current record id with Param("recordId").
The modern command designer adds buttons to model-driven command bars using Power Fx formulas with visibility and enable rules.
Package PCF components in a solution for ALM; pac pcf push targets only a development environment for testing.
Extend the platform
Pipeline stages are PreValidation (10) outside the transaction, PreOperation (20) inside it before save, and PostOperation (40) after save.
Register a Pre image on PostOperation steps to read the values that existed before the update; a Post image holds the saved values.
Throwing InvalidPluginExecutionException surfaces a business error to the user and rolls back the synchronous transaction.
Synchronous plug-ins block the user and share the database transaction; asynchronous plug-ins run in the background after commit.
Register assemblies in sandbox isolation mode; secure configuration is encrypted and readable only by the plug-in code.
A Custom API defines request and response parameters and binds to a plug-in type, avoiding per-table step registration.
Custom workflow activities derive from CodeActivity and surface as actions in Power Automate inside the solution.
Use ITracingService for diagnostics; trace output appears in the Plug-in Trace Log rather than the user error dialog.
Develop integrations
Base URL is https://{org}.api.crm.dynamics.com/api/data/v9.2/; send OData-Version and OData-MaxVersion 4.0 headers on every call.
Upsert: PATCH the entity set with the alternate key in parentheses and If-None-Match: * so a missing record is created.
Optimistic concurrency uses the ETag with If-Match; an HTTP 412 response means the record changed since it was read.
Group operations in a /$batch request; a changeset inside it is atomic, so one failure rolls back the whole set.
Enable change tracking, request Prefer: odata.track-changes, then reuse the returned delta token to fetch only changed rows.
Throttling returns HTTP 429 with a Retry-After header; the client must wait for that interval before retrying.
Server-to-server calls use an Azure AD app registration plus an application user holding a security role; no user license is consumed.
Impersonation uses the MSCRMCallerID header with a systemuserid and requires the prvActOnBehalfOfAnotherUser privilege.
Webhooks push POST JSON in near real time; Azure Service Bus endpoints add durable queues and topics with retry handling.