EF核心:添加具有十进制非身份PK

时间:2020-10-19 20:07:55

标签: c# entity-framework-core

我有一个现有的数据库,其中包含多个带有十进制(numeric(14,0))PK列的表。我正在尝试以不同的方式在一个动作中插入多个记录。

我不确定是否可以引入序列,所以我一直在尝试使用HasDefaultValueSql("MAX(CASE_ATTRIBUTE_ID) + 1")。在一般的用例中,您一次可以添加1-n CaseAttributes,因此我不必使用EF首先查询下一个ID。

如有必要,我可能会添加更多细节。但是,在没有自动递增标识列的情况下,用EF Core插入1-n记录的最佳方法通常是什么?

UDPATE:

实体类除外(我已经尝试过NoneComputed):

[ExcludeFromCodeCoverage]
[Table("CASE_ATTRIBUTE_CONFIG", Schema = "dbo")]
public partial class CaseAttribute : ISoftDelete, IUpdateTracker
{
    [Key]
    [Column("CASE_ATTRIBUTE_ID", TypeName = "numeric(14, 0)"), DatabaseGenerated(DatabaseGeneratedOption.None)]
    public decimal CaseAttributeId { get; set; }
}

上下文除外:

modelBuilder.Entity<CaseAttribute>(entity =>
{
    entity.Property(e => e.CaseAttributeId).HasDefaultValueSql("MAX(CASE_ATTRIBUTE_ID) + 1").ValueGeneratedOnAdd();

    entity.HasQueryFilter(e => EF.Property<DateTime?>(e, "EffectiveEndDate") == null);
});

如果我不使用ValueGeneratedOnAdd(),它似乎只是插入'0'。否则,我会遇到异常:Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while updating the entries. See the inner exception for details. ---> Microsoft.Data.SqlClient.SqlException (0x80131904): Cannot insert the value NULL into column 'CASE_ATTRIBUTE_ID', table 'RPE_V3_12_02_00.dbo.CASE_ATTRIBUTE_CONFIG'; column does not allow nulls. UPDATE fails.

使用探查器,您可以看到它还生成了一些非常奇怪的SQL:

exec sp_executesql N'SET NOCOUNT ON;
DECLARE @inserted0 TABLE ([CASE_ATTRIBUTE_ID] numeric(14, 0), [_Position] [int]);
MERGE [dbo].[CASE_ATTRIBUTE_CONFIG] USING (
VALUES (@p21, @p22, @p23, @p24, @p25, @p26, @p27, @p28, @p29, @p30, @p31, @p32, @p33, @p34, @p35, @p36, @p37, @p38, 0)) AS i ([CASE_ATTRIBUTE_NAME], [CASE_ATTRIBUTE_REGEX], [CASE_ATTRIBUTE_TYPE], [CASE_SUB_TYPE], [CASE_TYPE], [CODE], [CODE_TYPE], [CORE], [DISPLAY_GROUP_NAME], [DISPLAY_ORDER], [DISPLAY_TAB], [EFFECTIVE_BEGIN_DT], [EFFECTIVE_END_DT], [IS_REQUIRED], [MAXIMUM_LENGTH], [NODE_NAME], [UPDATED_BY], [UPDATED_DATE], _Position) ON 1=0
WHEN NOT MATCHED THEN
INSERT ([CASE_ATTRIBUTE_NAME], [CASE_ATTRIBUTE_REGEX], [CASE_ATTRIBUTE_TYPE], [CASE_SUB_TYPE], [CASE_TYPE], [CODE], [CODE_TYPE], [CORE], [DISPLAY_GROUP_NAME], [DISPLAY_ORDER], [DISPLAY_TAB], [EFFECTIVE_BEGIN_DT], [EFFECTIVE_END_DT], [IS_REQUIRED], [MAXIMUM_LENGTH], [NODE_NAME], [UPDATED_BY], [UPDATED_DATE])
VALUES (i.[CASE_ATTRIBUTE_NAME], i.[CASE_ATTRIBUTE_REGEX], i.[CASE_ATTRIBUTE_TYPE], i.[CASE_SUB_TYPE], i.[CASE_TYPE], i.[CODE], i.[CODE_TYPE], i.[CORE], i.[DISPLAY_GROUP_NAME], i.[DISPLAY_ORDER], i.[DISPLAY_TAB], i.[EFFECTIVE_BEGIN_DT], i.[EFFECTIVE_END_DT], i.[IS_REQUIRED], i.[MAXIMUM_LENGTH], i.[NODE_NAME], i.[UPDATED_BY], i.[UPDATED_DATE])
OUTPUT INSERTED.[CASE_ATTRIBUTE_ID], i._Position
INTO @inserted0;

SELECT [t].[CASE_ATTRIBUTE_ID] FROM [dbo].[CASE_ATTRIBUTE_CONFIG] t
INNER JOIN @inserted0 i ON ([t].[CASE_ATTRIBUTE_ID] = [i].[CASE_ATTRIBUTE_ID])
ORDER BY [i].[_Position];

',N'@p21 varchar(50),@p22 varchar(200),@p23 varchar(6),@p24 varchar(25),@p25 varchar(25),@p26 varchar(10),@p27 varchar(25),@p28 tinyint,@p29 varchar(100),@p30 decimal(1,0),@p31 varchar(25),@p32 datetime,@p33 datetime,@p34 bit,@p35 decimal(1,0),@p36 varchar(25),@p37 varchar(128),@p38 datetime',@p21='test-attribute',@p22=NULL,@p23='STR',@p24='ADMIN',@p25='MYTEST',@p26='MN',@p27='STATE_PROVINCE',@p28=4,@p29='display-group',@p30=1,@p31='',@p32='2020-10-01 00:00:00',@p33=NULL,@p34=0,@p35=4,@p36='node-name',@p37='admin@rsimail.com',@p38='2020-10-19 21:03:03.787'

1 个答案:

答案 0 :(得分:0)

我不确定是否可以引入序列,

是否有技术上的理由不使用Sequences

您正在配置EF以无论如何在服务器端生成该值。序列可以更高效地生成值(并且EF不需要知道它是如何生成的),并且具有额外的好处,即您通过SQL Management Studio执行的手动插入操作也会利用序列。

您可以添加一个空的EF迁移(dotnet ef migrations add ...),以创建序列并更新表以使用序列的下一个值作为主键的默认值。

假设当前的MAX(CaseAttributeId)5000

CREATE SEQUENCE [dbo].[CaseAttributeIdSequence] AS NUMERIC(14,0)
    START WITH 5001
    MINVALUE 5001
    INCREMENT BY 1
;

更新表以将序列的下一个值用作默认值:

ALTER TABLE [dbo].[CaseAttribute]
    ADD CONSTRAINT [DF_CaseAttribute_CaseAttributeId]
        DEFAULT NEXT VALUE FOR [dbo].[CaseAttributeIdSequence]
        FOR [CaseAttributeId]
;