Repository navigation
Added in Cosmos Model Config for polymorphic properties, ModelMapRegistry and mapping fixes
AppFactory Framework v10.8.0
🧬 CosmosDB: polymorphic properties
Entities can now store and restore properties typed as an abstract or base class, holding any derived type. You configure the hierarchy once in your IModelConfig<TModel>. No attributes on domain classes and no CLR type names in the stored data.
public void Configure(IModelConfigOptions<Department> config)
{
config.ContainerName("departments").Id(d => d.Id).PartitionKey(d => d.TenantId);
// Applies wherever Person is used: properties, arrays, lists, dictionary values, nested objects
config.Polymorphic<Person>()
.DiscriminateOn("type")
.WithValue<Person>("person")
.WithValue<Manager>("manager")
.DefaultTo<Person>(); // for documents stored before this existed
// Optional override for a single property
config.Map(d => d.Persons)
.DiscriminateOn("personType")
.WithValue<Person>("person")
.WithValue<Manager>("manager");
}
Stored as:
{ "id": "D1", "tenantId": "T1", "head": { "type": "manager", "name": "Ann", "reports": [{ "type": "person", "name": "Bob" }] } }
The discriminator is a regular field, so you can query it: SELECT * FROM c WHERE c.head.type = 'manager'
Renaming or moving classes doesn't break stored data
Configuration mistakes are reported when the mapping is built, and unknown or unregistered types are reported with the JSON path
⚡ CosmosDB: model mapping built once
The new IModelMapRegistry (registered by RegisterCosmosDbPersistence()) runs each IModelConfig<TModel> once per application. Previously it ran on every request.
🐛 CosmosDB fixes
Nested properties are stored again. Nested objects lost properties with the same name as the root's Id or partition key, for example Department.Persons[i].Id.
The configured Id property is restored. With Id(e => e.EmployeeNumber), EmployeeNumber came back null when read.
No more silent Id loss. If another property stored as id holds a different value than the configured Id, the write now throws instead of overwriting it.
⚠️ Upgrade notes
Deprecated: the RepositoryBase constructor taking IModelConfig<TModel>. Switch to IModelMapRegistry:
public UserRepository(ICosmosDbClientFactory factory, ILogger logger, IModelMapRegistry modelMapRegistry)
: base(factory, logger, modelMapRegistry) { }
IModelConfigOptions<TModel> has two new members, Polymorphic<TBase>() and Map(...). Only custom implementations of this interface are affected.
Documents without polymorphism are written exactly as before, so existing data keeps working.
A null partition key value read into a value-type property now gets its default value instead of throwing.
Full details: [CHANGELOG.md](vscode-webview://1o5190jvn8uc4un39vjbn0ali3ne16qicsdbeu1v64mivgr7vckt/CHANGELOG.md#1080---2026-10-19)