Chapter 04 / 09
ENSK

SmartExchange · .NET 10 · Chapter 04

Generated relationship registry

The registry connects CRM declarations to three consumers: the Context Resolver, scope validation and the SQL mapping factory.

Shared code · Intaker + Web APIReviewed · 2026-10-27

Where the registry is used

ConsumerCall / responsibility
SmartExchangeAuthorizationContextResolver.ResolveAsync()GetRelationships(resource) → select grant resource kinds: root plus direct declaration targets.
SmartExchangeAuthorizationScopeValidatorGenerate(diagram) → allow named scope pairs only when that resource declares the target.
Application mapping, through AuthorizationSqlMappingFactory.Create()Convert the same relationship steps into correlated SQL subqueries.

SmartExchangeAuthorizationRelationshipRegistry.Generate(DiagramCrm) produces AuthorizationRelationship records: resource kind, attribute alias, target kind/key and join steps. GetRelationships(string) returns definitions for one resource; ScopeValidator exposes cached metadata validation.

Registry use in both examples

Registry output / usePerson exportInterestedParty export
Attributeresource.attr.companyIdsresource.attr.projectIds
TargetResourceKindCompanyProject
Generated pathPerson → PersonInCompany → CompanyInterestedParty → Project
Resolver selectionPerson + CompanyInterestedParty + Project + Investor
Scope validationCompany/read/Resource is a direct Company fact.InterestedParty/read/Project requires the declared pair.
SQL enforcementEXISTS PersonInCompany JOIN CompanyEXISTS Project

Both relationships supply trusted SQL structure; the policy chooses why a grant qualifies. The resolver retains all actions/scopes for selected kinds and does not recursively traverse their other relations. Investor is selected for InterestedParty because it is also directly annotated; this demo policy does not consume Investor grants.

Person relationship JSON · InterestedParty relationship JSON

Scope normalization and validation

MethodImplemented behavior
LegacySqlAuthorizationGrantAdapter.Normalize()Instance assignment → Instance scope; same entity → Resource scope; different declared target → named scope. Cross-entity conversion also requires unique canonical permission ownership.
ValidateResource(resource)Require a known CRM entity name, with exact casing.
SupportsScope(resource, scope)Accept Resource, Instance or a declared resource→target pair.
Validate(grant)Validate resource/scope, nonblank action and a nonempty record ID except for Instance scope.
Example: InterestedParty/read assigned on Project becomes InterestedParty / read / Project. Project/read does not turn into InterestedParty/read. Validation checks metadata and contract consistency; the policy still decides access.

Registry generation also rejects ambiguous paths, duplicate aliases and unsupported key/deletion metadata. SQL adds Deleted = 0 at every relationship step; the application retains the root query’s deletion filter.