I'm having issue in Insertion of data in Temporal table
using C# Entity Framework
The Table schema is
CREATE TABLE People(
PeopleID int PRIMARY KEY NOT NULL,
Name varchar(50) Null,
LastName varchar(100) NULL,
NickName varchar(25),
StartTime datetime2 GENERATED ALWAYS AS ROW START NOT NULL,
EndTime datetime2 GENERATED ALWAYS AS ROW END NOT NULL,
PERIOD FOR SYSTEM_TIME (StartTime,EndTime)
) WITH (SYSTEM_VERSIONING = ON(HISTORY_TABLE = dbo.PeopleHistory));
I created an EDMX asusal and I tried to Insert a record using following C# Code
using (var db = new DevDBEntities()) {
People1 peo = new People1() {
PeopleID = 1,
Name = "Emma",
LastName = "Watson",
NickName = "ICE"
};
db.Peoples.Add(peo);
db.SaveChanges();
}
I got an exception while on db.SaveChanges()
"Cannot insert an explicit value into a GENERATED ALWAYS column in table 'DevDB.dbo.People'. Use INSERT with a column list to exclude the GENERATED ALWAYS column, or insert a DEFAULT into GENERATED ALWAYS column."
I tried direct insertion using SQL Server using the following Insert Query, its inserting fine.
INSERT INTO [dbo].[People]
([PeopleID]
,[Name]
,[LastName]
,[NickName])
VALUES
(2
,'John'
,'Math'
,'COOL')
Kindly assist me how to insert an record using C# Entity Framework.
Probably the simplest solution would be manually edit the .EDMX file and remove all traces of the StartTime and EndTime columns.
Light summary: The problem occurs when EF trying to update values inside
PERIOD
system versioning column which the column property values are managed by SQL Server itself.From MS Docs: Temporal tables, the temporal table works as a pair of current table and history table which explained as this:
As both
StartTime
&EndTime
column are automatically generated, they must be excluded from any attempt to insert or update values on them. Here are these steps to get rid of the error, assuming you're in EF 6:StartTime
&EndTime
column properties asIdentity
inStoreGeneratedPattern
option. This prevents EF refreshing values on anyUPDATE
events.Create a custom command tree interceptor class which implements
System.Data.Entity.Infrastructure.Interception.IDbCommandTreeInterceptor
and specify set clauses which should be set asReadOnlyCollection<T>
(T is aDbModificationClause
) which cannot be modified by EF in insert or update modifications:Still in the same class above, create list of ignored table names and define actions in INSERT and UPDATE commands, the method should be looks like this (credits to Matt Ruwe for this method):
Register the interceptor class above before database context usage in another code part either by using
DbInterception
:or attach it in context definition using
DbConfigurationTypeAttribute
:Related issues:
Entity Framework not working with temporal table
Getting DbContext from implementation of IDbCommandInterceptor
Hooking IDbInterceptor to EntityFramework DbContext only once