1

私は 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
4

2 に答える 2

1

Aエンティティを削除する前に、すべてのBエンティティを削除するだけです[更新]
最初にデータベースであるため、Bクラスに含まれているという事実

  public int A_ID { get; set; }

あなたが説明したような関係ではないと思います。
データベース図で見てみてください。

于 2013-06-02T20:10:48.980 に答える
0

この動作は EF によって意図されているため、DbContext を使用して WPF アプリケーションの回避策を使用しました。この問題は、ウィンドウの有効期間中に DbContext インスタンスを使用するために発生します。したがって、コンテキスト内のオブジェクト グラフは、ウィンドウが閉じられるまで一貫している必要があります。外部キー制約またはデータベース接続障害が原因で削除操作が失敗した場合、remove メソッド中にオブジェクト グラフが変更されます。回避策として、次のメソッドを実装しました。

  1. エンティティを削除する前に、外部キー制約を確認してください。ロードされたオブジェクト グラフのみが影響を受けるため、ロードされたエンティティのみをチェックする必要があります。ビジネス ロジックは、すべての制約を既に認識している EF とは別にこのチェックを実装する必要があるため、これは完全に満足できるものではありません。

  2. 別の DbContext でエンティティを削除する この方法では、削除に失敗しても元のコンテキストは変更されません。これは、ウィンドウが削除されたエンティティと同等である状況ではうまく機能します。この場合、削除操作が成功するとウィンドウは閉じられ、削除操作が失敗すると元のコンテキストで開いたままになります。ただし、サブエンティティの削除が失敗する状況は、この方法ではカバーされていません。

最後に、削除操作の失敗後にコンテキスト全体を更新できますが、この場合、以前に設定されたエンティティのすべての変更が失われます。

于 2013-06-06T22:16:30.203 に答える