SQL Server 插入触发器未使用 EF 触发

问题描述 投票:0回答:1

我有这个插入触发器,可以处理重复的键插入尝试:

-- Create Tigger to not throw in case of duplicate mapping attempt

CREATE TRIGGER dbo.BlockDuplicates_Product_Category_Mapping
 ON dbo.Product_Category_Mapping
 INSTEAD OF INSERT
AS
BEGIN
  SET NOCOUNT ON;
  IF NOT EXISTS (SELECT 1 FROM inserted AS i 
    INNER JOIN dbo.Product_Category_Mapping AS p
    ON i.ProductId = p.ProductId
    AND i.CategoryId = p.CategoryId
  )
  BEGIN
    INSERT dbo.Product_Category_Mapping(ProductId, CategoryId, IsFeaturedProduct, DisplayOrder)
      SELECT ProductId, CategoryId, IsFeaturedProduct, DisplayOrder FROM inserted;
  END
  ELSE
  BEGIN
    PRINT 'Duplicate';
  END
END

如果我直接从 DBMS 运行它,它就可以正常工作:

但是,如果我在带有 EF 的代码中使用它:

<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.15" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="3.1.15" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.15" />

它似乎不起作用,抛出了重复的键异常,这正是我试图避免的:

Microsoft.EntityFrameworkCore.Relational:更新条目时发生错误。有关详细信息,请参阅内部异常。核心 Microsoft SqlClient 数据提供程序:违反 UNIQUE KEY 约束“UQ_PCM_ProductId_CategoryId”。无法在对象“dbo.Product_Category_Mapping”中插入重复的键。重复的键值为 (920, 129)。

这是通过导航属性插入的(如果有任何区别的话)。

有人可以向我指出为什么这不起作用吗?

我遵循了这两个相关问题,但我没有看到任何可以帮助的内容:

SQL Server 2008 插入触发器未触发

SQL Server 2008 - 插入触发器未触发

c# sql-server entity-framework-core triggers
1个回答
0
投票

我要再次敲鼓:这个想法是一个的想法。给应用程序/用户留下事情“有效”的印象,而实际上却没有,这不是一个好主意。在这种情况下,你说这“不是问题”,但我可以自信地说,在某些时候,用户会问“为什么我刚才添加的产品在我要求的时候没有出现”。答案将是“您的

INSERT
被忽略了,但我们为您掩盖了该错误并且没有告诉您。”

话虽如此,如果您“必须”()在触发器中执行此操作,那么您的处理方式就是错误的。如果您要插入多行,这将会出现各种错误,就好像其中 1 行是重复的,您会忽略所有行。插入 100 个新产品,其中 1 个是骗局?您插入

相反,使用

INSERT
NOT EXISTS
并将其余部分“分类”。不理想,您的用户会感到困惑,但这似乎是您所追求的行为,至少:

CREATE TRIGGER dbo.BlockDuplicates_Product_Category_Mapping
ON dbo.Product_Category_Mapping
INSTEAD OF INSERT
AS
BEGIN
    SET NOCOUNT ON;

    INSERT INTO dbo.Product_Category_Mapping (ProductId,
                                              CategoryId,
                                              IsFeaturedProduct,
                                              DisplayOrder)
    SELECT i.ProductId,
           i.CategoryId,
           i.IsFeaturedProduct,
           i.DisplayOrder
    FROM inserted i
    WHERE NOT EXISTS (SELECT 1
                      FROM dbo.Product_Category_Mapping PCM
                      WHERE PCM.ProductId = i.ProductId
                        AND PCM.CategoryId = i.CategoryId);
END;

如果您真的想善待您的用户(以避免他们在未插入内容时感到困惑),您可以进行更新插入。然后,您

UPDATE
已存在的行,到他们想要的值
INSERT
,以及
INSERT
新行。

CREATE TRIGGER dbo.BlockDuplicates_Product_Category_Mapping
ON dbo.Product_Category_Mapping
INSTEAD OF INSERT
AS
BEGIN
    SET NOCOUNT ON;

    --No need to define a transaction, as a trigger is already inside one and automatically has XACT_ABORT enabled

    UPDATE PCM
    SET IsFeaturedProduct = i.IsFeaturedProduct,
        DisplayOrder = i.DisplayOrder
    FROM dbo.Product_Category_Mapping PCM WITH (UPDLOCK, SERIALIZABLE)
        JOIN inserted i ON PCM.ProductId = i.ProductId
                       AND PCM.CategoryId = i.CategoryId;

    INSERT INTO dbo.Product_Category_Mapping (ProductId,
                                              CategoryId,
                                              IsFeaturedProduct,
                                              DisplayOrder)
    SELECT i.ProductId,
           i.CategoryId,
           i.IsFeaturedProduct,
           i.DisplayOrder
    FROM inserted i
    WHERE NOT EXISTS (SELECT 1
                      FROM dbo.Product_Category_Mapping PCM
                      WHERE PCM.ProductId = i.ProductId
                        AND PCM.CategoryId = i.CategoryId);
END;
© www.soinside.com 2019 - 2024. All rights reserved.