2017-05-24 4 views
2

INSTEAD OFトリガを使用するいくつかのテーブルで構成される更新可能なビューを作成したシナリオがあります。 SSMSを使用して手動でこのビューに挿入できることを確認しました。しかし、私のアプリケーションがビューを表現するためにEF Code-Firstを使用しているので、レコードを挿入しようとすると、EFが挿入ステートメントの後のSELECTでSCOPE_IDENTITY()を使用したために問題が発生します。私はscope_identity()のインクルードを「強制」するトリガの最後に文を含めようとしましたが、成功しませんでした。私はまた、幸運と私の挿入ステートメントにOUTPUTオプションを含めることを試みた。自分のシナリオがEFが処理するにはあまりにも複雑かどうか疑問に思っていますか?フィードバックに基づいてEFコードを使用して更新可能なビューを挿入/更新する方法

、私は非常に皆のために再現するのは簡単です何かにこのシナリオを簡素化しています:

関連するテーブルとビューの定義:

IF NOT EXISTS(SELECT * FROM [sysobjects] WHERE [type] = 'U' AND [name] = 'Parent') 
BEGIN 
    CREATE TABLE [dbo].[Parent] 
    (
     [ent_pk] INT IDENTITY(1,1) NOT NULL, 
     [ent_id] VARCHAR(25) DEFAULT('') NOT NULL, 
     CONSTRAINT [PK_Parent] PRIMARY KEY CLUSTERED ([ent_pk]) 
    ) 
END 
GO 
IF NOT EXISTS(SELECT * FROM [sysobjects] WHERE [type] = 'U' AND [name] = 'Child1') 
BEGIN 
    CREATE TABLE [dbo].[Child1] 
    (
     [c1_entfk] INT NOT NULL, 
     [c1_field1] VARCHAR(30) DEFAULT('') NOT NULL, 
     [c1_fees] DECIMAL(7,2) DEFAULT(0) NOT NULL, 
     CONSTRAINT [PK_Child1] PRIMARY KEY CLUSTERED ([c1_entfk]) 
    ) 
END 
GO 
IF EXISTS(SELECT * FROM sys.views WHERE [object_id] = OBJECT_ID(N'[dbo].[vwView]')) 
    DROP VIEW [dbo].[vwView] 
GO 
CREATE VIEW [dbo].[vwView] AS 
SELECT [ent_pk], 
    [ent_id], 
    [c1_field1], 
    [c1_fees] 
    FROM [Parent] 
     LEFT JOIN [Child1] ON [c1_entfk] = [ent_pk] 
GO 

次のようにトリガー・コードは次のとおりです。

IF EXISTS(SELECT * FROM sysobjects WHERE [type] = 'TR' AND [name] = 'trg_vwView_i') 
    DROP TRIGGER [trg_vwView_i] 
GO 
CREATE TRIGGER [trg_vwView_i] ON [dbo].[vwView] INSTEAD OF INSERT 
AS 
BEGIN 
    INSERT INTO [Parent] ([ent_id]) 
     SELECT [ent_id] 
     FROM [Inserted] [I] 

    INSERT INTO [Child1] ([c1_entfk], [c1_field1], [c1_fees]) 
     SELECT [E].[ent_pk], [c1_field1], [c1_fees] 
     FROM [Inserted] [I] 
      INNER JOIN [Parent] [E] ON [E].[ent_id] = [I].[ent_id] 
END 
GO 

上記の表とビューの定義に含まれていない外部キー制約のため、親レコードは最初に挿入する必要があります。参照整合性を維持するために、他のテーブル内のレコードをnsertingします。

そしてPOCOクラスの定義は次のとおりです。

[Table("vwView")] 
public class SimpleViewTest 
{ 

    [Key] 
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
    public int ent_pk { get; set; } 

    [MaxLength(25)] 
    public string ent_id { get; set; } 

    [MaxLength(30)] 
    public string c1_field1 { get; set; } 

    public decimal c1_fees { get; set; } 

} 

挿入用EFによって生成されたSQLのサンプル:SSMSで上記のSQL文を実行

exec sp_executesql N'INSERT [dbo].[vwView]([ent_id], [c1_field1], [c1_fees]) 
VALUES (@0, @1, @2) 
SELECT [ent_pk] 
FROM [dbo].[vwView] 
WHERE @@ROWCOUNT > 0 AND [ent_pk] = scope_identity()',N'@0 nvarchar(25),@1 nvarchar(30),@2 decimal(7,2) ',@0=N'AK FED CU',@1=N'Alaska Federal Credit Union',@2=10.00 

は、正しくレコードを挿入様々なテーブルに。しかし、SCOPE_IDENTITY()がNULLを返すため、selectには何も返されません。

私はSCOPE_IDENTITY()に[Parent]テーブルへの挿入の値を返す方法や、それが可能なのかどうかはわかりません。誰かがこれができるかどうか、あるいはこの種のシナリオを処理するストアドプロシージャの定義を探る必要があるかどうかを知っていますか?または、人々が持っている他の提案はありますか?

注:私は「フラット」オブジェクトではなく、複数のオブジェクトで構成される一つとして、自分のアプリケーション内のエンティティを表現したい...

+0

あなたのコードはあまりにもSQLを読むのには時間がかかりすぎますので、簡単に理解して読んでください。 –

+0

あなたの提案をありがとうございます。私はオリジナルの投稿を編集して、シナリオを簡素化し、それに従うのがずっと簡単になるはずです –

答えて

0

[OK]をクリックします。 EFのドキュメントにもっと詳しく掘り下げた後、私はこれを見つけた:https://msdn.microsoft.com/en-us/library/dn469464(v=vs.113).aspx。さらに、IDbCommandInterceptorの実装に関して、次のBLOG投稿が見つかりました。ここでは、実行前にEFによって生成されたSQLを変更できることを参照しています:https://www.skylinetechnologies.com/Blog/Skyline-Blog/December-2013/Entity-Framework-6-Intercepting-SQL-produced

だから、次のように私の解決策は、私自身のIDbCommandInterceptorを実装し、ReaderExecuitingメソッドをオーバーライドすることでした:

public void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) 
{ 
    string sqlToIntercept = "INSERT [dbo].[vwView]"; 

    if (command.CommandText.Contains(sqlToIntercept)) 
    { 
     command.CommandText = command.CommandText.Replace("WHERE @@ROWCOUNT > 0 AND [ent_pk] = scope_identity()", "WHERE @@ROWCOUNT > 0 AND [ent_id] = @1"); 
    } 
} 

を、この問題のすべての可能な変化に完全に適していないが、私の場合、それは非常に動作しませんParentテーブルのent_idフィールドがビジネスルールのために一意でなければならないのでうまくいきます。

このシナリオが遭遇する類似のシナリオとまったく同じではない場合でも、このソリューションは、特定のシナリオを解決するための追加の方向性を提供する可能性があります。

これを読み、コメントする時間がかかりました皆様に感謝します。ではごきげんよう。

関連する問題