私は WPF アプリケーションで DbContext と Database-First アプローチで EF5 を使用していますが、次のシナリオでエンティティの削除と必要なデータ注釈属性の使用中にいくつかの論理的な問題に遭遇しました。
カスケード削除なしで外部キーを使用して相互に参照する 2 つのテーブルがあります。
|----A----| |----B----|
|ID int |<-| |ID int |
|---------| |-|A_ID int |
したがって、「B」が「A」を参照している場合、「A」は削除できません。
EF 5 モデルには関連付けが含まれており、カスケードが設定されていないため、関連付けの両端で OnDelete が "None" に設定されています。「A_ID」フィールドとナビゲーション プロパティ「BA」の両方を [Required] 属性で装飾しました。ここで、この「A」エンティティを参照する「B」エンティティを含む「A」エンティティを削除すると、問題が発生します。
MyContext.Set<A>().Remove(MyA);
MyContext.SaveChanges();
SaveChanges は、削除された "A" エンティティに対する "B" のすべてのナビゲーション プロパティを null に設定します。ナビゲーション プロパティには Required-Attribute があり、「B」が無効であるため「A」を削除できないという例外がスローされるため、これは「B」を無効にします。これはどういうわけか奇妙な理由です。
ただし、Navigation プロパティの Required-Attribute を削除し、B.A_ID プロパティの Required-Attribute をそのままにしておくと、正しいエラーがスローされます。
最後に、データベースの例外の後、「A」のすべてのナビゲーション プロパティが「null」に設定されたオブジェクト グラフになります。
これは EF の意図した動作だと思いますが、これは 2 つの問題につながります。
まず、削除操作が無効です。「削除」検証については何も見つかりませんでした。データ注釈は、プロパティの変更のみを考慮します。
次に、すべてのナビゲーション プロパティが「null」に設定されているため、例外の後に削除されたエンティティを回復する方法。EF 5 アソシエーションは、アソシエーションで「なし」、「NULL に設定」、または「カスケード」を許可する SQL Server のものほど正確ではありません。"None" の場合、SQL Server は例外をスローし、すべてのエンティティを変更しません。
データベース例外の後に "CanDelete" 検証とエンティティ リカバリの同じ問題に遭遇し、解決策を持っているか、他の関連スレッドを教えてくれる場合は、教えてください。
あなたの、
マーカス
クラスの例:
// Entity to delete
public partial class A {
public A() {
this.Bs = new HashSet<B>();
}
public int ID { get; set; }
public Nullable<int> C_ID { get; set; }
public string Name { get; set; }
public virtual C C { get; set; }
public virtual ICollection<B> Bs { get; set; }
}
// Child entities of A with foreign key constraint
public partial class B {
public int ID { get; set; }
public int A_ID { get; set; }
public string Name { get; set; }
public virtual A A { get; set; }
}
// Example class of an additional entity referencing A
public partial class C {
public C() {
this.As = new HashSet<A>();
}
public int ID { get; set; }
public string Name { get; set; }
public virtual ICollection<A> As { get; set; }
}
データベース スキーマ:
CREATE DATABASE [EFABC]
GO
USE [EFABC]
GO
CREATE TABLE [dbo].[tA](
[ID] [int] IDENTITY(1,1) NOT NULL,
[C_ID] [int] NULL,
[Name] [nvarchar](50) NULL,
CONSTRAINT [PK_tA] PRIMARY KEY CLUSTERED
(
[ID] ASC
) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[tB](
[ID] [int] IDENTITY(1,1) NOT NULL,
[A_ID] [int] NOT NULL,
[Name] [nvarchar](50) NULL,
CONSTRAINT [PK_tB] PRIMARY KEY CLUSTERED
(
[ID] ASC
) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[tC](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](50) NULL,
CONSTRAINT [PK_tC] PRIMARY KEY CLUSTERED
(
[ID] ASC
) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[tA] WITH CHECK ADD CONSTRAINT [FK_tA_tC] FOREIGN KEY([C_ID])
REFERENCES [dbo].[tC] ([ID])
GO
ALTER TABLE [dbo].[tA] CHECK CONSTRAINT [FK_tA_tC]
GO
ALTER TABLE [dbo].[tB] WITH CHECK ADD CONSTRAINT [FK_tB_tA] FOREIGN KEY([A_ID])
REFERENCES [dbo].[tA] ([ID])
GO
ALTER TABLE [dbo].[tB] CHECK CONSTRAINT [FK_tB_tA]
GO