web-dev-qa-db-ja.com

Entity Framework SaveChangesがトリガーにより失敗する

既存のデータベース(SQL Server 2012)にEntity Frameworkを実装しようとしています。 VBアプリケーションを実行しており、それをEFベースのWeb APIに変換しようとしています。

テーブルInboundEquipmentにデータを挿入すると、InboundEquipmentIDIDENTITY列になります。また、このテーブルにはInboundEquipmentIDを使用して別のテーブル_Message214Status_に挿入する挿入トリガーがあります。これらのテーブル間のFK関係はありません。

データベースオブジェクト:

_CREATE TABLE [dbo].[InboundEquipment](
    [InboundEquipmentID] [bigint] IDENTITY(1,1) NOT NULL,
    ...

CREATE TABLE [dbo].[Message214Status](
    [InboundEquipmentID] [bigint] NOT NULL, 
    ...

ALTER TRIGGER [dbo].[InboundEquipment] ON [dbo].[InboundEquipment] FOR INSERT AS
DECLARE
    @biInbndEquip_ID    BIGINT,
    @iCust_ID           INT,
    ...
SELECT  @biInbndEquip_ID= InboundEquipmentID,@iCust_ID= c.Cust_ID,  ...
FROM
    INSERTED I
    JOIN sometable c WITH(NOLOCK)ON ...
INSERT INTO dbo.Message214Status (InbndEquip_ID,    Cust_ID) VALUES
    (@biInbndEquip_ID,@iCust_ID )
...
_

私のVBコード:

_db.InboundEquipment.Add(ibData);
try
{
    db.SaveChanges();
    var IBEquipID = ibData.InboundEquipmentID;
}
catch (Exception ex)
{
    return ResponseMessage(Request.CreateErrorResponse (HttpStatusCode.InternalServerError, "ERROR:" + ex.Message));
}

public partial class InboundEquipment
{
    [Key] 
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public long InboundEquipmentID { get; set; }
    ...
_

DBContext.db.SaveChanges()は次の例外で失敗します:

InnerException {「値NULLを列 'InboundEquipmentID'、テーブル 'dbo.Message214Status'に挿入できません。列はnullを許可しません。INSERTは失敗します。\ r\nステートメントが終了しました。」} System.Exception {System.Data.SqlClient .SqlException}

基本的に、挿入トリガーは失敗します。変更できないこのデータベースに依存する別の既存のアプリケーションがあるため、データベースオブジェクトを変更できません。

挿入トリガーを無効にすると、保存が正常に完了します。

トリガーが失敗した理由は何ですか?

3
user107189

ほとんどの場合、sometableへのJOINに問題があり、行が一致しないように除外されているため、@biInbndEquip_ID変数が入力されることはありません。

ただし、それを修正しても、対処する必要がある大きな問題があります。トリガーロジックは、単一の行を処理するように記述されています。複数行のINSERTが実行されると、トリガーはMessage214Statusテーブルに配置するために挿入された値の1つのみを取得します。トリガーの@biInbndEquip_ID@iCust_IDなどのローカル変数を削除し、単純なINSERT...SELECTに書き換えます。例えば:

INSERT INTO dbo.Message214Status (InbndEquip_ID, Cust_ID, ...)
  SELECT ins.[InboundEquipmentID], ins.[CustID], ...
  FROM   INSERTED ins
  INNER JOIN sometable c
          ON c.[join_column] = ins.[join_column];
4
Solomon Rutzky