You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
) WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = ['+ @historyTableSchema + N'].[EmployeeHistory]))');
65
65
```
66
66
67
-
Notice that SQL Server creates two hidden `datetime2` columns called `PeriodEnd` and `PeriodStart`. These "period columns" represent the time range during which the data in the row existed. These columns are mapped to [shadow properties](xref:core/modeling/shadow-properties) in the EF Core model, allowing them to be used in queries as shown later.
67
+
Notice that SQL Server creates two hidden `datetime2` columns called `PeriodEnd` and `PeriodStart`. These "period columns" represent the time range during which the data in the row existed. By default, these columns are mapped to [shadow properties](xref:core/modeling/shadow-properties) in the EF Core model, allowing them to be used in queries as shown later. Starting with EF Core 11, period columns can also be [mapped to CLR properties](#mapping-period-columns-to-clr-properties) on your entity type.
68
68
69
69
> [!IMPORTANT]
70
70
> The times in these columns are always UTC time generated by SQL Server. UTC times are used for all operations involving temporal tables, such as in the queries shown below.
Also, after a normal [tracking query](xref:core/querying/tracking#no-tracking-queries), the values from the period columns of the current data can be [accessed from the tracked entities](xref:core/change-tracking/entity-entries). For example:
151
+
Also, after a normal [tracking query](xref:core/querying/tracking#no-tracking-queries), the values from the period columns of the current data can be [accessed from the tracked entities](xref:core/change-tracking/entity-entries). If the period columns are mapped to CLR properties, you can access them directly on the entity; otherwise, use `EF.Property` to access them as shadow properties. For example:
152
152
153
153
<!--
154
154
var employees = context.Employees.ToList();
@@ -212,7 +212,7 @@ foreach (var pointInTime in history)
Notice how the [EF.Property method](xref:core/modeling/shadow-properties#accessing-shadow-properties) can be used to access values from the period columns. This is used in the `OrderBy` clause to sort the data, and then in a projection to include these values in the returned data.
215
+
Notice how the [EF.Property method](xref:core/modeling/shadow-properties#accessing-shadow-properties) can be used to access values from the period columns. This is used in the `OrderBy` clause to sort the data, and then in a projection to include these values in the returned data. If the period columns are [mapped to CLR properties](#mapping-period-columns-to-clr-properties), you can reference them directly in the query instead of using `EF.Property`.
216
216
217
217
This query brings back the following data:
218
218
@@ -280,3 +280,62 @@ Historical data for Rainbow Dash:
280
280
Employee Rainbow Dash was 'Wonderbolt' from 8/26/2021 4:43:29 PM to 8/26/2021 4:44:59 PM
281
281
Employee Rainbow Dash was 'Wonderbolt Trainee' from 8/26/2021 4:44:59 PM to 12/31/9999 11:59:59 PM
282
282
```
283
+
284
+
## Mapping period columns to CLR properties
285
+
286
+
> [!NOTE]
287
+
> This feature is being introduced in EF Core 11, which is currently in preview.
288
+
289
+
By default, the period columns in a temporal table are mapped to [shadow properties](xref:core/modeling/shadow-properties) in the EF Core model, meaning they don't need to exist on your .NET entity type. Starting with EF Core 11, you can instead map period columns to regular CLR properties on your entity type, which allows you to access their values directly.
290
+
291
+
To do this, add `DateTime` properties for the period start and end to your entity type:
292
+
293
+
```csharp
294
+
publicclassEmployee
295
+
{
296
+
publicGuidEmployeeId { get; set; }
297
+
publicstringName { get; set; }
298
+
publicstringPosition { get; set; }
299
+
publicstringDepartment { get; set; }
300
+
publicstringAddress { get; set; }
301
+
publicdecimalAnnualSalary { get; set; }
302
+
publicDateTimePeriodStart { get; set; }
303
+
publicDateTimePeriodEnd { get; set; }
304
+
}
305
+
```
306
+
307
+
Then configure the temporal table to use these properties via a lambda expression:
308
+
309
+
```csharp
310
+
modelBuilder
311
+
.Entity<Employee>()
312
+
.ToTable(
313
+
"Employees",
314
+
b=>b.IsTemporal(
315
+
b=>
316
+
{
317
+
b.HasPeriodStart(e=>e.PeriodStart);
318
+
b.HasPeriodEnd(e=>e.PeriodEnd);
319
+
}));
320
+
```
321
+
322
+
> [!NOTE]
323
+
> Period properties are automatically configured with `ValueGenerated.OnAddOrUpdate`, so their values are always generated by SQL Server. You don't need to — and should not — set their values when inserting or updating entities.
324
+
325
+
When period columns are mapped to CLR properties, you can access their values directly on the entity instead of using `EF.Property`:
Copy file name to clipboardExpand all lines: entity-framework/core/what-is-new/ef-core-11.0/whatsnew.md
+44Lines changed: 44 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -394,6 +394,50 @@ WHERE JSON_CONTAINS([b].[JsonData], 8, N'$.Rating') = 1
394
394
395
395
For the full `JSON_CONTAINS` SQL Server documentation, see [`JSON_CONTAINS`](/sql/t-sql/functions/json-contains-transact-sql).
396
396
397
+
<aname="sqlserver-temporal-clr-properties"></a>
398
+
399
+
### Temporal period properties mapped to CLR properties
400
+
401
+
Previously, the period properties (`PeriodStart`/`PeriodEnd`) on temporal tables were required to be [shadow properties](xref:core/modeling/shadow-properties), meaning they existed only in the EF model and not as CLR properties on your .NET entity types. Starting with EF Core 11, period properties can now be mapped to regular CLR properties on the entity type, making it easier to access their values directly without using `EF.Property`.
402
+
403
+
To map period columns to CLR properties, add `DateTime` properties to your entity type and configure them with the lambda-based `HasPeriodStart`/`HasPeriodEnd` overloads:
404
+
405
+
```csharp
406
+
publicclassEmployee
407
+
{
408
+
publicGuidEmployeeId { get; set; }
409
+
publicstringName { get; set; }
410
+
publicstringPosition { get; set; }
411
+
publicDateTimePeriodStart { get; set; }
412
+
publicDateTimePeriodEnd { get; set; }
413
+
}
414
+
415
+
modelBuilder
416
+
.Entity<Employee>()
417
+
.ToTable(
418
+
"Employees",
419
+
b=>b.IsTemporal(
420
+
b=>
421
+
{
422
+
b.HasPeriodStart(e=>e.PeriodStart);
423
+
b.HasPeriodEnd(e=>e.PeriodEnd);
424
+
}));
425
+
```
426
+
427
+
Once period properties are mapped to CLR properties, you can reference them directly in LINQ queries — for example, in `OrderBy`, `Select`, or `Where` clauses — without needing `EF.Property`:
Period properties remain configured with `ValueGenerated.OnAddOrUpdate`, so their values are always generated by SQL Server and excluded from INSERT and UPDATE statements.
438
+
439
+
For more information, see the [full documentation on temporal tables](xref:core/providers/sql-server/temporal-tables#mapping-period-columns-to-clr-properties).
0 commit comments