私はこれを理解しようとしばらく探していました。複合主キーを使用してテーブルを作成しようとしています。キーの最初の部分は、親テーブルへの外部キーでもあります。2番目の部分は、SQLServerで自動生成されます。だから、私はこのように見えるはずのテーブルを持っています:
ParentId ChildId
-------- -------
1 1
1 2
1 3
2 1
2 2
2 3
2 4
ChildId列は、ParentIdのコンテキスト内でのみ一意です。値は、INSTEAD OF INSERTトリガーを使用してサーバー上で自動生成されるため、各ChildIdは独自のシーケンスを持ちます。
私の問題は、これはSQL Serverおよび従来のADO.NETSqlCommand
ステートメント内でうまく機能しますが、EntityFrameworkはこれを使用したくないということです。
ChildId列のStoreGeneratedPatternをIdentityに設定すると、EFは次のようなSQLを生成します。
insert [dbo].[ChildTable]([ParentId], [Name])
values (@0, @1)
select [ChildId]
from [dbo].[ChildTable]
where @@ROWCOUNT > 0 and [ParentId] = @0 and [Id] = scope_identity()
これはエラーを生成するだけです:
System.Data.Entity.Infrastructure.DbUpdateConcurrencyException:ストアの更新、挿入、または削除ステートメントが予期しない行数(0)に影響しました。エンティティがロードされてから、エンティティが変更または削除された可能性があります。ObjectStateManagerエントリを更新します。
----> System.Data.OptimisticConcurrencyException:ストアの更新、挿入、または削除ステートメントが予期しない行数(0)に影響しました。エンティティがロードされてから、エンティティが変更または削除された可能性があります。ObjectStateManagerエントリを更新します。
ただし、GUIDに基づくキーを使用してテストテーブルを作成し、StoreGeneratedPatternをIdentityに設定すると、生成されるSQLは次のようになります。
declare @generated_keys table([Id] uniqueidentifier)
insert [dbo].[GuidTable]([Name])
output inserted.[Id] into @generated_keys
values (@0)
select t.[Id]
from @generated_keys as g join [dbo].[GuidTable] as t on g.[Id] = t.[Id]
where @@ROWCOUNT > 0
また、アプリケーションのエンティティは、SQLServerが生成したGUIDの値で更新されます。
つまり、Entity Frameworkが値を取得するために、列がIDENTITY列である必要はないことを示しています。ただし、論理テーブルを使用しているためinserted
、ChildIdの値は変更された値にはなりません。トリガーによって。また、inserted
テーブルにUPDATE操作を適用して、値をトリガー内にプッシュバックすることはできません(「論理テーブルINSERTEDおよびDELETEDは更新できません」と表示されました)。
私はここの隅に戻ったような気がしますが、設計を再考する前に、Entity Frameworkを介してChildId値をアプリケーションに戻す方法はありますか?