尝试使用Entity Framework Core 2.1插入时态表时出现以下错误。
无法在表'db_test.dbo.Department'的GENERATED ALWAYS列中插入显式值。将INSERT与列列表一起使用可排除GENERATED ALWAYS列,或将DEFAULT插入GENERATED ALWAYS列。
下面是我的表架构
with open(f, "r") as infile:
我的CREATE TABLE Department
(
DeptID int NOT NULL PRIMARY KEY CLUSTERED,
DeptName varchar(50) NOT NULL,
ManagerID INT NULL,
ParentDeptID int NULL,
SysStartTime datetime2 GENERATED ALWAYS AS ROW START NOT NULL,
SysEndTime datetime2 GENERATED ALWAYS AS ROW END NOT NULL,
PERIOD FOR SYSTEM_TIME (SysStartTime, SysEndTime)
)
WITH
(
SYSTEM_VERSIONING = ON (HISTORY_TABLE = dbo.DepartmentHistory)
)
;
看起来像这样:
DbContext
请看看,让我知道如何解决此问题。我不喜欢修改db上下文类,因为我是使用DBScaffold通过nuget控制台生成它的,因此每次重新生成它时,都无法手动对其进行更新。
答案 0 :(得分:2)
使“周期开始”列(SysStartTime)和“周期结束”列(SysEndTime)应该可以解决此问题。我们可以通过
ALTER TABLE [dbo].[Department] ALTER COLUMN [SysStartTime] ADD HIDDEN;
ALTER TABLE [dbo].[Department] ALTER COLUMN [SysEndTime] ADD HIDDEN;
我们可以在sys.columns表中看到针对这些列的隐藏设置
SELECT * FROM sys.columns WHERE is_hidden = 1
答案 1 :(得分:0)
entity.Property(e => e.Modified).HasComputedColumnSql("GENERATED ALWAYS AS ROW START");
代码的“有效地”列中添加OnModelCreating
。我正在将.NET Core 2.2与EntityFrameworkCore 3.0 Preview 6一起使用。
我没有将HIDDEN
属性添加到@VPP答案中的那些列中,而是发现添加HasComputedColumnSql
可以解决问题 ,这也意味着EF在每次添加后都检索该列UPDATE
。
这是我的CREATE TABLE
:
CREATE TABLE [dbo].[Contacts] (
[ContactId] INT NOT NULL IDENTITY,
[TenantId] INT NOT NULL,
[Created] DATETIME2 (7) NOT NULL,
[Modified] DATETIME2 (7) GENERATED ALWAYS AS ROW START NOT NULL,
[ValidTo] DATETIME2 (7) GENERATED ALWAYS AS ROW END NOT NULL CONSTRAINT [DF_Contacts_ValidTo] DEFAULT ('9999-12-31 23:59:59.9999999'),
[Name] NVARCHAR(255) NOT NULL,
[PhoneNumber] NVARCHAR(255) NOT NULL,
[HasAMulletHaircut] BIT NOT NULL,
[ListensToDevo] BIT NOT NULL,
[Status] INT NOT NULL,
CONSTRAINT PK_Contacts PRIMARY KEY ([ContactId], [TenantId]),
CONSTRAINT [FK_Contacts_Tenants] FOREIGN KEY ([TenantId]) REFERENCES dbo.Tenants( TenantId ),
PERIOD FOR SYSTEM_TIME ([Modified], [ValidTo])
)
WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE=[dbo].[Contacts_History], DATA_CONSISTENCY_CHECK=ON));
这是我的模型构建器代码的样子(最初由dotnet ef dbcontext scaffold
生成,带有我的修改标记):
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Contact>(entity =>
{
entity.HasKey(e => new { e.ContactId, e.TenantId });
// I added this:
entity.Property(e => e.Modified).HasComputedColumnSql("GENERATED ALWAYS AS ROW START");
// I added this, then commented it out because properties cannot have both `HasComputedColumnSql` and `HasDefaultValueSql`. But it works anyway.
//entity.Property(e => e.ValidTo).HasComputedColumnSql("GENERATED ALWAYS AS ROW END");
entity.Property(e => e.ValidTo).HasDefaultValueSql("('9999-12-31 23:59:59.9999999')");
entity.HasOne(d => d.Tenant)
.WithMany(p => p.Contacts)
.HasForeignKey(d => d.TenantId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_Contacts_Tenants");
});
简而言之:
entity.Property(e => e.Modified).HasComputedColumnSql("GENERATED ALWAYS AS ROW START");
。我运行了测试,并且INSERT
和UPDATE
语句运行正常(请注意,我的代码根本不会修改我的“有效期自”或“有效期至”属性)。
如上所述,这种方法的优势在于,在调用SaveChanges
/ SaveChangesAsync
之后,EF将自动获取“有效自”列的更新/新值。
答案 2 :(得分:0)
您可以将有效日期时间到/自列设置为“隐藏=真”。然后EF不在乎,您的临时版本无需任何额外工作即可工作。当EF支持它(3.0ish)时,您应该可以使用.FromSql($“ SELECT * FROM dbo.Products FOR SYSTEM_TIME AS OF {{0}}”,date.ToUniversalTime())来过滤该数据,但是大多数前端只关心最近的数据,因此对我们大多数人来说可能不是问题。