Ошибка при вставке во временную таблицу с использованием Entity Framework Core 2.1 - PullRequest
0 голосов
/ 04 октября 2018

Я получаю приведенную ниже ошибку при попытке вставить во временную таблицу с использованием Entity Framework Core 2.1.

Невозможно вставить явное значение в столбец GENERATED ALWAYS в таблице 'db_test.dbo.Департамент».Используйте INSERT со списком столбцов, чтобы исключить столбец GENERATED ALWAYS, или вставьте DEFAULT в столбец GENERATED ALWAYS.

Ниже приведена схема моей таблицы

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выглядит так:

modelBuilder.Entity<Department>(entity =>
            {
                entity.HasKey(e => e.DeptId);

                entity.Property(e => e.DeptId)
                    .HasColumnName("DeptID")
                    .ValueGeneratedNever();

                entity.Property(e => e.DeptName)
                    .IsRequired()
                    .HasMaxLength(50)
                    .IsUnicode(false);

                entity.Property(e => e.ManagerId).HasColumnName("ManagerID");

                entity.Property(e => e.ParentDeptId).HasColumnName("ParentDeptID");
            });

Пожалуйста, взгляните и дайте мне знать, как мы можем это исправить.Я не фанат изменения класса контекста db, так как я генерирую его через консоль nuget с использованием DBScaffold, и я не могу обновлять его вручную каждый раз, когда мы его заново генерируем.

Ответы [ 3 ]

0 голосов
/ 01 июля 2019

TL; DR:

  • Добавьте entity.Property(e => e.Modified).HasComputedColumnSql("GENERATED ALWAYS AS ROW START"); для своего столбца "valid from" в коде 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));

Вот как выглядит мой код Model Builder (изначально сгенерированный 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"); для своего столбца "valid from".
  • Вам не нужно ничего делать для своего столбца "valid to".

Я выполнил тесты и INSERT и UPDATE операторы работают нормально (обратите внимание, что мой код вообще не изменяет мои свойства «valid from» или «valid to»).

Как упоминалось выше, преимуществоэтот подход заключается в том, что после вызова SaveChanges / SaveChangesAsync EF будет автоматически получать обновленные / новые значения для столбца «valid from».

0 голосов
/ 29 июля 2019

Вы можете установить временную дату, допустимую для столбцов / из столбцов, в значение «Скрыто» = «Истина».Тогда EF не волнует, и ваша временная версия работает без какой-либо дополнительной работы.Когда EF поддерживает его (3.0ish), вы сможете использовать .FromSql ($ "SELECT * FROM dbo.Products FOR SYSTEM_TIME AS OF {{0}}", date.ToUniversalTime ()) для фильтрации этих данных, но большинства внешних интерфейсов.заботятся только о последних данных, поэтому для большинства из нас это может не быть проблемой.

0 голосов
/ 08 ноября 2018

Создание столбца начала периода (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 
...