entity framework不使用时态表

我正在使用数据库第一entity framework6.在将我的模式中的一些表更改为临时表后,我在尝试插入新数据时开始收到以下错误:

Cannot insert an explicit value into a GENERATED ALWAYS column in table '.dbo.. Use INSERT with a column list to exclude the GENERATED ALWAYS column, or insert a DEFAULT into GENERATED ALWAYS column.

看起来EF正在尝试更新由系统管理的PERIOD列的值。

从EDMX文件中删除列似乎可以解决问题,但这不是一个可行的解决方案,因为每次从数据库重新生成模型时都会重新添加列。

这个问题有两种解决方案:

  1. 在EDMX设计器中列的属性窗口中,将PERIOD列(我的情况下为ValidFrom和ValidTo)上的StoreGeneratedPattern更改为identitycomputed 。 标识可能更好,因为计算将导致EF刷新插入和更新上的值,而不是仅具有identity的插入
  2. 创建一个IDbCommandTreeInterceptor实现以删除句点列。 这是我首选的解决方案,因为在向模型添加新表时不需要额外的工作。

这是我的实现:

 using System.Data.Entity.Infrastructure.Interception; using System.Data.Entity.Core.Common.CommandTrees; using System.Data.Entity.Core.Metadata.Edm; using System.Collections.ObjectModel; internal class TemporalTableCommandTreeInterceptor : IDbCommandTreeInterceptor { private static readonly List _namesToIgnore = new List { "ValidFrom", "ValidTo" }; public void TreeCreated(DbCommandTreeInterceptionContext interceptionContext) { if (interceptionContext.OriginalResult.DataSpace == DataSpace.SSpace) { var insertCommand = interceptionContext.Result as DbInsertCommandTree; if (insertCommand != null) { var newSetClauses = GenerateSetClauses(insertCommand.SetClauses); var newCommand = new DbInsertCommandTree( insertCommand.MetadataWorkspace, insertCommand.DataSpace, insertCommand.Target, newSetClauses, insertCommand.Returning); interceptionContext.Result = newCommand; } var updateCommand = interceptionContext.Result as DbUpdateCommandTree; if (updateCommand != null) { var newSetClauses = GenerateSetClauses(updateCommand.SetClauses); var newCommand = new DbUpdateCommandTree( updateCommand.MetadataWorkspace, updateCommand.DataSpace, updateCommand.Target, updateCommand.Predicate, newSetClauses, updateCommand.Returning); interceptionContext.Result = newCommand; } } } private static ReadOnlyCollection GenerateSetClauses(IList modificationClauses) { var props = new List(modificationClauses); props = props.Where(_ => !_namesToIgnore.Contains((((_ as DbSetClause)?.Property as DbPropertyExpression)?.Property as EdmProperty)?.Name)).ToList(); var newSetClauses = new ReadOnlyCollection(props); return newSetClauses; } } 

在使用上下文之前,通过在代码中的任何位置运行以下命令来向EF注册此拦截器:

 DbInterception.Add(new TemporalTableCommandTreeInterceptor()); 

另一种解决方案是在表的字段中创建默认约束。

 CREATE TABLE [dbo].[Table] ( [Id] INT IDENTITY(1, 1) NOT NULL, [Description] NVARCHAR(100) NOT NULL, [ValidFrom] DATETIME2(0) GENERATED ALWAYS AS ROW START HIDDEN CONSTRAINT [Df_Table_ValidFrom] DEFAULT DATEADD(SECOND, -1, SYSUTCDATETIME()), [ValidTo] DATETIME2(0) GENERATED ALWAYS AS ROW END HIDDEN CONSTRAINT [Df_Table_ValidTo] DEFAULT '9999.12.31 23:59:59.99', PERIOD FOR SYSTEM_TIME ([ValidFrom], [ValidTo]), CONSTRAINT [Pk_Table] PRIMARY KEY CLUSTERED ([Id] ASC) ) WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = [dbo].[Table_History])); GO 

在代码中不需要改动。