Repository navigation
6.0.0
The headline feature of v6 is Fluent Entity support: a new way to store multiple entity types polymorphically in a single Azure Table Storage table. The release also brings automatic partition key query optimization, a smarter CreateIfNotExistsMode, and improved change-tracking defaults.
New packages
| Package | Description |
|---|---|
TableStorage.Fluent |
Polymorphic fluent entities, 2 to 4 types per table |
TableStorage.Fluent.Extended |
Same, for 5 to 16 types per table |
TableStorage.Fluent.RuntimeCompilations |
Runtime LINQ compilation for fluent queries |
What's new
Fluent entities
Store multiple entity types in a single table using a type discriminator. Define your models as usual and compose them:
[TableContext]
public partial class MyTableContext
{
public TableSet<FluentTableEntity<Customer, Order>> MixedEntities { get; set; }
}Three discriminator strategies are supported:
FluentTableEntity<T1, T2>: stores a$typepropertyFluentPartitionTableEntity<T1, T2>: usesPartitionKeyas discriminatorFluentRowTypeTableEntity<T1, T2>: usesRowKeyas discriminator
Fluent entities support implicit conversions in both directions, GetBackingType(), GetActualType(), GetValue() / GetValueOrDefault(), and pattern matching via SwitchCase / SwitchCaseOrDefault.
Source-generated named extension methods for fluent types
The source generator now emits named Where* and FindAsync* methods derived from the actual type names on each fluent table set. A TableSet<FluentTableEntity<Customer, Order>> property gets WhereCustomer(...) and WhereOrder(...) generated automatically, with no need to call WhereFirstType / WhereSecondType by hand.
Partition key query optimization
A new OptimizeQueries option on TableOptions (enabled by default) automatically splits OR conditions that span multiple partition keys into parallel per-partition queries, instead of a full-table scan:
// Executed as two parallel partition-scoped queries
await foreach (var entity in context.MyTable.Where(x => x.PartitionKey == "a" || x.PartitionKey == "b")) { }Opt out via options.OptimizeQueries = false.
CreateIfNotExistsMode
The old boolean CreateTableIfNotExists / CreateContainerIfNotExists options are replaced by an enum with three values:
| Value | Behavior |
|---|---|
Disabled |
Assumes the resource already exists; never attempts creation |
Once |
Creates once per process lifetime; result is cached in memory |
Always |
Always attempts creation on use (previous behavior) |
Once is useful for dynamic table/container scenarios where you want to avoid repeated round-trips after the first successful creation.
Improvements
- Change tracking defaults to
Merge: whenChangesOnly = true, update and bulk operations now automatically useMergeinstead ofReplace, preventing unchanged properties from being overwritten with default values. - Fluent merge support:
FluentMergeVisitorAndValidatorcorrectly handles merging for fluent types whenChangesOnlyis enabled. - Reduced allocations: internal refactoring of
FluentTableEntityreduces heap allocations in high-throughput scenarios. internalTableSets + fluent types:internalTableSet properties can now be source-generated in combination with fluent entity types.- Namespace clash prevention: the source generator no longer emits code into namespaces that could conflict with user-defined types.