Skip to content

Allow configuring SQL Server temporal table period columns as not hidden#38225

Open
m-x-shokhzod wants to merge 5 commits intodotnet:mainfrom
m-x-shokhzod:feat/sqlserver-period-columns-not-hidden
Open

Allow configuring SQL Server temporal table period columns as not hidden#38225
m-x-shokhzod wants to merge 5 commits intodotnet:mainfrom
m-x-shokhzod:feat/sqlserver-period-columns-not-hidden

Conversation

@m-x-shokhzod
Copy link
Copy Markdown
Contributor

@m-x-shokhzod m-x-shokhzod commented May 5, 2026

Adds TemporalPeriodPropertyBuilder.IsHidden(bool hidden = true) to opt individual SQL Server temporal table period columns out of the HIDDEN flag. Default remains HIDDEN to preserve backward compatibility. Each period column is independently configurable.

Per @roji's review feedback, IsHidden is exposed as a general SQL Server property facet (mirroring IsSparse), not a temporal-specific flag — forward-compatible with future non-temporal HIDDEN scenarios.

  • New annotation SqlServerAnnotationNames.IsHidden (property + column level)
  • New annotations SqlServerAnnotationNames.TemporalPeriodStartHidden / TemporalPeriodEndHidden (table level, lifted by SqlServerAnnotationProvider for the migrations differ)
  • Property extensions IsHidden / SetIsHidden (mutable + convention) / GetIsHiddenConfigurationSource on SqlServerPropertyExtensions (mirrors IsSparse pattern)
  • IsHidden(bool hidden = true) method added to TemporalPeriodPropertyBuilder and OwnedNavigationTemporalPeriodPropertyBuilder
  • Annotation propagated through SqlServerAnnotationProvider (per-period-column) and SqlServerMigrationsSqlGenerator — conditional HIDDEN SQL emit in both ColumnDefinition (CREATE TABLE path) and EnablePeriod (ALTER TABLE convert-to-temporal path)
  • Snapshot fluent-API generation chains .IsHidden(false) per period property; runtime annotation strip in SqlServerCSharpRuntimeAnnotationCodeGenerator
  • 2 migrations functional tests in MigrationsSqlServerTest.TemporalTables (Create_temporal_table_with_period_columns_not_hidden, Convert_normal_table_to_temporal_with_visible_period_columns) verified against real SQL Server in CI matrix (2019/2022/2025); 3 model-builder tests in SqlServerModelBuilderTestBase; baseline.json entries updated for new public surface

Fixes #36608

Adds TemporalTableBuilder.PeriodColumnsHidden(bool hidden = true) to opt out
of the HIDDEN flag on period start/end columns. Default remains HIDDEN to
preserve backward compatibility.

Fixes dotnet#36608
@m-x-shokhzod m-x-shokhzod requested a review from a team as a code owner May 5, 2026 18:04
Period columns are shadow properties at the model level regardless of the
HIDDEN SQL flag, so the IColumn collection only exposes Id and Name. The
HIDDEN flag affects emitted SQL only, not table.Columns.
@roji
Copy link
Copy Markdown
Member

roji commented May 6, 2026

Good complement to #38110, which we've already done for preview-4.

Some quick notes:

  • Am noting that SQL Server allows configuring HIDDEN on a per-column basis, not just on the pair.
  • SQL Server seems to support HIDDEN in other contexts, e.g. on GENERATED ALWAYS AS columns. I haven't done a thorough investigation here, but is it worth treating HIDDEN as a general SQL Server property facet, as opposed to something completely specific to temporal tables?
  • We preferring adding migration test coverage in MigrationsSqlServerTest rather than SqlServerMigrationsSqlGenerator - the latter just asserts on the generated SQL, whereas the former actually executes the migration and ensures it works.

/cc @AndriySvyryd

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces an opt-out for SQL Server temporal table period columns being created as HIDDEN, via new fluent API TemporalTableBuilder.PeriodColumnsHidden(bool hidden = true). This preserves the existing default (HIDDEN) for backwards compatibility while allowing period columns to be visible in SELECT * when explicitly configured.

Changes:

  • Adds a new model annotation (SqlServerAnnotationNames.TemporalPeriodColumnsHidden) and entity-type extension APIs to store/read the setting (defaulting to true when not configured).
  • Extends all temporal table builders (regular/generic + owned navigation regular/generic) with PeriodColumnsHidden(...).
  • Propagates the annotation through design-time model annotation generation and SQL generation, adding a functional migrations test and model-building tests.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
test/EFCore.SqlServer.FunctionalTests/ModelBuilding/SqlServerModelBuilderTestBase.cs Adds model-building tests asserting default hidden behavior and explicit visibility via PeriodColumnsHidden(false), plus test builder plumbing.
test/EFCore.SqlServer.FunctionalTests/Migrations/MigrationsSqlServerTest.TemporalTables.cs Adds a migrations functional test verifying CREATE TABLE SQL omits HIDDEN when configured.
src/EFCore.SqlServer/Migrations/SqlServerMigrationsSqlGenerator.cs Emits HIDDEN conditionally for period columns based on the new annotation; strips the annotation in some temporal-migration normalization paths.
src/EFCore.SqlServer/Metadata/Internal/SqlServerAnnotationProvider.cs Flows the “not hidden” configuration into design-time annotations for tables and for the period start/end columns.
src/EFCore.SqlServer/Metadata/Internal/SqlServerAnnotationNames.cs Introduces the TemporalPeriodColumnsHidden annotation name constant.
src/EFCore.SqlServer/Metadata/Builders/TemporalTableBuilder`.cs Adds the generic builder PeriodColumnsHidden(...) (return-type narrowing wrapper).
src/EFCore.SqlServer/Metadata/Builders/TemporalTableBuilder.cs Adds the core temporal table builder API PeriodColumnsHidden(...) to set the new entity-type annotation.
src/EFCore.SqlServer/Metadata/Builders/OwnedNavigationTemporalTableBuilder``.cs Adds the generic owned-navigation builder PeriodColumnsHidden(...) (return-type narrowing wrapper).
src/EFCore.SqlServer/Metadata/Builders/OwnedNavigationTemporalTableBuilder.cs Adds the core owned-navigation temporal table builder API PeriodColumnsHidden(...).
src/EFCore.SqlServer/Extensions/SqlServerEntityTypeExtensions.cs Adds IsTemporalPeriodColumnsHidden / SetIsTemporalPeriodColumnsHidden (mutable + convention) and configuration-source accessors.
src/EFCore.SqlServer/EFCore.SqlServer.baseline.json Updates API baseline for the newly-added public surface area.
src/EFCore.SqlServer/Design/Internal/SqlServerCSharpRuntimeAnnotationCodeGenerator.cs Strips the new annotation from runtime annotation output (consistent with other temporal annotations).
src/EFCore.SqlServer/Design/Internal/SqlServerAnnotationCodeGenerator.cs Adds snapshot fluent API generation for .PeriodColumnsHidden(false) and removes the annotation afterward.

Comment on lines +1886 to +1892
// Defaults to true to preserve backward compatibility - the period columns have always been hidden.
// Set to false via TemporalTableBuilder.PeriodColumnsHidden(false) to make them visible.
var hidden = operation[SqlServerAnnotationNames.TemporalPeriodColumnsHidden] as bool? ?? true;
if (hidden)
{
builder.Append(" HIDDEN");
}
Addresses feedback on PR dotnet#38225:

- roji dotnet#1: per-column HIDDEN configuration → IsHidden(bool) on
  TemporalPeriodPropertyBuilder + OwnedNavigationTemporalPeriodPropertyBuilder
  lets users hide the start and end columns independently.
- roji dotnet#2: HIDDEN as a property facet rather than a temporal-specific entity
  setting → new SqlServerAnnotationNames.IsHidden plus SqlServerPropertyExtensions
  IsHidden / SetIsHidden / GetIsHiddenConfigurationSource (mirroring IsSparse).
  PeriodColumnsHidden(bool) is preserved on TemporalTableBuilder as a convenience
  that calls SetIsHidden on both period properties.
- Copilot bug: convert-to-temporal path was always emitting
  ALTER COLUMN ... ADD HIDDEN. Two new table-level annotations
  TemporalPeriodStartHidden / TemporalPeriodEndHidden are emitted by
  SqlServerAnnotationProvider.For(ITable) when a period property is configured
  visible. BuildTemporalInformationFromMigrationOperation reads them into
  TemporalOperationInformation, and EnablePeriod skips the ADD HIDDEN
  ALTER COLUMN operations when the column is configured visible.
- New functional test Convert_normal_table_to_temporal_with_visible_period_columns
  asserts the ADD HIDDEN operations are omitted.
- Snapshot generator chains .IsHidden(false) onto the period property fluent
  call when the column is configured visible.
- Removed entity-level TemporalPeriodColumnsHidden annotation and the
  IsTemporalPeriodColumnsHidden / SetIsTemporalPeriodColumnsHidden /
  GetIsTemporalPeriodColumnsHiddenConfigurationSource entity extensions.
- Updated baseline.json accordingly.
@m-x-shokhzod m-x-shokhzod force-pushed the feat/sqlserver-period-columns-not-hidden branch from 6956bbd to 76554e0 Compare May 6, 2026 11:29
The pair-level convenience PeriodColumnsHidden(bool) on TemporalTableBuilder
had a silent-no-op bug: when called before HasPeriodStart/HasPeriodEnd, the
period property names were not yet set, so the implementation could not find
the properties to call SetIsHidden on.

The property-level IsHidden(bool) on TemporalPeriodPropertyBuilder is order-safe
because it chains directly off HasPeriodStart/HasPeriodEnd which return the
period property builder for the property that was just configured. It also
matches roji's preference for HIDDEN as a property-level facet rather than a
temporal-table-specific entity setting.

- Removed PeriodColumnsHidden from TemporalTableBuilder + generic +
  OwnedNavigationTemporalTableBuilder + generic
- Removed corresponding abstract / override methods from test wrappers
- Updated functional tests to chain IsHidden(false) per period property:
    ttb.HasPeriodStart("Start").IsHidden(false);
    ttb.HasPeriodEnd("End").IsHidden(false);
- Updated baseline.json (4 entries removed)

This also fixes the CI failure on Convert_normal_table_to_temporal_with_visible_period_columns
on SqlServer 2019/2022/2025: the test was using PeriodColumnsHidden(false)
inside ToTable(...IsTemporal(...)) before period property names were set,
making the call a no-op and leaving ALTER COLUMN ... ADD HIDDEN in the
emitted SQL.
In RewriteOperations, the AlterTableOperation case builds the temporal
information from alterTableOperation.OldTable to capture the initial
(non-temporal) state. But that source has no TemporalPeriodStartHidden /
TemporalPeriodEndHidden annotations, so PeriodStartHidden/PeriodEndHidden
defaulted to true and EnablePeriod always emitted ALTER COLUMN ... ADD
HIDDEN, ignoring the user's IsHidden(false) configuration.

Override just those two flags from alterTableOperation itself, which
carries the target-state annotations emitted by SqlServerAnnotationProvider.
All other initial-state reads from OldTable remain intact.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow configuring period columns as not hidden

3 participants