5

Tôi đang sử dụng khung thực thể cơ sở dữ liệu đầu tiên 6. Sau khi thay đổi một số bảng trong lược đồ của tôi thành bảng thời gian, tôi bắt đầu nhận được lỗi sau khi cố gắng chèn dữ liệu mới:Khung thực thể không hoạt động với bảng thời gian

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

Có vẻ như EF đang cố cập nhật giá trị của các cột PERIOD do hệ thống quản lý.

Xóa các cột khỏi tệp EDMX dường như khắc phục được sự cố, nhưng đây không phải là giải pháp khả thi do các cột được thêm lại mỗi lần mô hình được tạo lại từ cơ sở dữ liệu.

Trả lời

7

Có hai giải pháp cho vấn đề này:

  1. Trong cửa sổ thuộc tính cho cột trong thiết kế EDMX, thay đổi StoreGeneratedPattern trên PERIOD cột (ValidFrom và ValidTo trong trường hợp của tôi) là một trong hai identity hoặc computed. Danh tính có lẽ tốt hơn kể từ khi tính toán sẽ làm cho EF làm mới các giá trị trên Chèn và Cập nhật thay vì chỉ chèn bằng identity
  2. Tạo triển khai IDbCommandTreeInterceptor để loại bỏ các cột thời gian. Đây là giải pháp ưa thích của tôi vì nó không yêu cầu thêm công việc khi thêm các bảng mới vào mô hình.

Dưới đây là thực hiện của tôi:

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<string> _namesToIgnore = new List<string> { "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<DbModificationClause> GenerateSetClauses(IList<DbModificationClause> modificationClauses) 
    { 
     var props = new List<DbModificationClause>(modificationClauses); 
     props = props.Where(_ => !_namesToIgnore.Contains((((_ as DbSetClause)?.Property as DbPropertyExpression)?.Property as EdmProperty)?.Name)).ToList(); 

     var newSetClauses = new ReadOnlyCollection<DbModificationClause>(props); 
     return newSetClauses; 
    } 
} 

ký đánh chặn này với EF bằng cách chạy sau bất cứ nơi nào trong mã của bạn trước khi bạn sử dụng ngữ cảnh của bạn:

DbInterception.Add(new TemporalTableCommandTreeInterceptor()); 
+0

Tôi có thể làm điều tương tự với lõi khung thực thể như thế nào? –

+0

@AramGevorgyan - Bạn có thể sử dụng thuộc tính [DatabaseGenerated (DatabaseGeneratedOption.Computed)] trên thuộc tính hoặc sử dụng phương thức Fluent API .ValueGeneratedOnAddOrUpdate() ví dụ: entity.Property (e => e.ValidFrom) .ValueGeneratedOnAddOrUpdate(); [xem tại đây] (http://www.learnentityframeworkcore.com/configuration/data-annotation-attributes/databasegenerated-attribute) để tham khảo. –

+1

Làm việc như một sự quyến rũ! 'Usings' là như sau' using System.Data.Entity.Infrastructure.Interception; bằng System.Data.Entity.Core.Common.CommandTrees; bằng System.Data.Entity.Core.Metadata.Edm; sử dụng System.Collections.ObjectModel; ' – mike123

0

Một giải pháp khác là tạo ra hạn chế mặc định trong các lĩnh vực của bảng.

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 

Trong mã không cần thay đổi gì.

Các vấn đề liên quan