197

テーブルに制約を追加しようとすると問題が発生します。エラーが発生します:

テーブル「Employee」にFOREIGNKEY制約「FK74988DB24B3C886」を導入すると、サイクルまたは複数のカスケードパスが発生する可能性があります。ON DELETENOACTIONまたはONUPDATENO ACTIONを指定するか、他のFOREIGNKEY制約を変更します。

私の制約はCodeテーブルとテーブルの間にありemployeeます。Codeテーブルには、、、、およびがId含まれます。にはコードを参照するフィールドがいくつかあるため、コードのタイプごとに参照することができます。NameFriendlyNameTypeValueemployee

参照されているコードが削除された場合、フィールドをnullに設定する必要があります。

どうすればこれを行うことができますか?

4

11 に答える 11

198

SQL Server はカスケード パスの単純なカウントを行い、循環が実際に存在するかどうかを調べようとするのではなく、最悪の事態を想定して参照アクション (CASCADE) の作成を拒否します。設計を変更できない場合 (または変更すると問題が発生する場合) は、最後の手段としてトリガーを使用することを検討してください。

カスケード パスを解決する FWIW は複雑な問題です。他の SQL 製品は単純に問題を無視し、サイクルを作成できるようにします。その場合、おそらく設計者の無知により、どちらが最後に値を上書きするかを競うことになります (たとえば、ACE/Jet はこれを行います)。一部の SQL 製品は単純なケースを解決しようとすることを理解しています。事実は残っています.SQL Serverは試みさえせず、複数のパスを許可しないことで非常に安全であり、少なくともそう伝えます.

Microsoft 自身、FK 制約の代わりにトリガーを使用することを推奨しています。

于 2009-05-12T10:03:56.847 に答える
117

複数のカスケード パスを使用する典型的な状況は次のとおりです。2 つの詳細 ("Master"、"Detail1"、"Detail2" など) を持つマスター テーブル。どちらの詳細もカスケード削除です。これまでのところ問題はありません。しかし、両方の詳細が他のテーブル ("SomeOtherTable" など) と 1 対多の関係にある場合はどうなるでしょうか。SomeOtherTable には Detail1ID 列と Detail2ID 列があります。

Master { ID, masterfields }

Detail1 { ID, MasterID, detail1fields }

Detail2 { ID, MasterID, detail2fields }

SomeOtherTable {ID, Detail1ID, Detail2ID, someothertablefields }

つまり、SomeOtherTable の一部のレコードは Detail1 レコードにリンクされ、SomeOtherTable の一部のレコードは Detail2 レコードにリンクされています。SomeOtherTable-records が両方の Details に決して属さないことが保証されている場合でも、Master から SomeOtherTable への複数のカスケード パス (Detail1 経由と Detail2 経由) があるため、SomeOhterTable のレコードを両方の詳細に対してカスケード削除することは現在不可能です。今、あなたはすでにこれを理解しているかもしれません。考えられる解決策は次のとおりです。

Master { ID, masterfields }

DetailMain { ID, MasterID }

Detail1 { DetailMainID, detail1fields }

Detail2 { DetailMainID, detail2fields }

SomeOtherTable {ID, DetailMainID, someothertablefields }

すべての ID フィールドはキー フィールドであり、自動インクリメントです。核心は、詳細テーブルの DetailMainId フィールドにあります。これらのフィールドは、キー制約と参照制約の両方です。マスターレコードのみを削除することで、すべてをカスケード削除できるようになりました。欠点は、detail1 レコードごとに、detail2 レコードごとに、DetailMain レコードも存在する必要があることです (実際には、正しい一意の ID を取得するために最初に作成されます)。

于 2010-08-23T13:55:17.177 に答える
14

(機能的に) SCHEMA と DATA のサイクルや複数のパスには大きな違いがあることを指摘しておきます。DATA 内のサイクルとおそらくマルチパスは確かに処理を複雑にし、パフォーマンスの問題 (「適切な」処理のコスト) を引き起こす可能性がありますが、スキーマ内のこれらの特性のコストはゼロに近いはずです。

RDB の明らかなサイクルのほとんどは階層構造 (組織図、パート、サブパートなど) で発生するため、SQL Server が最悪の事態を想定しているのは残念です。つまり、スキーマ サイクル == データ サイクルです。実際、RI 制約を使用している場合、実際にデータ内にサイクルを構築することはできません!

マルチパスの問題も似ていると思います。つまり、スキーマ内の複数のパスは必ずしもデータ内の複数のパスを意味するわけではありませんが、マルチパスの問題についてはあまり経験がありません。

もちろん、SQL Serverでサイクル許可されていれば、深さは 32 のままですが、ほとんどの場合はこれで十分でしょう。(残念ながら、これはデータベースの設定ではありません!)

「削除の代わりに」トリガーも機能しません。2 回目にテーブルにアクセスすると、トリガーは無視されます。したがって、カスケードを本当にシミュレートしたい場合は、サイクルが存在する状態でストアド プロシージャを使用する必要があります。ただし、代わりの削除トリガーは、マルチパスの場合に機能します。

Celko は、サイクルを導入しない階層を表す「より良い」方法を提案していますが、トレードオフがあります。

于 2010-05-04T19:29:02.167 に答える
8

トリガーを使用して複数の削除パスを実行する方法を説明している記事があります。多分これは複雑なシナリオに役立ちます。

http://www.mssqltips.com/sqlservertip/2733/solving-the-sql-server-multiple-cascade-path-issue-with-a-trigger/

于 2015-05-28T14:38:50.837 に答える
3

その音によって、既存の外部キーの1つに対してOnDelete / OnUpdateアクションがあり、コードテーブルが変更されます。

したがって、この外部キーを作成することにより、循環的な問題を作成することになります。

たとえば、従業員を更新すると、更新時アクションによってコードが変更され、更新時アクションによって従業員が変更されます...など...

両方のテーブルのテーブル定義と外部キー/制約定義を投稿すると、問題がどこにあるかを知ることができるはずです...

于 2009-05-12T07:52:03.457 に答える
2

これは、従業員が資格と言う他のエンティティのコレクションを持っている可能性があり、資格が他のコレクションの大学を持っている可能性があるためです。

public class Employee{
public virtual ICollection<Qualification> Qualifications {get;set;}

}

public class Qualification{

public Employee Employee {get;set;}

public virtual ICollection<University> Universities {get;set;}

}

public class University{

public Qualification Qualification {get;set;}

}

DataContext では、以下のようになります

protected override void OnModelCreating(DbModelBuilder modelBuilder){

modelBuilder.Entity<Qualification>().HasRequired(x=> x.Employee).WithMany(e => e.Qualifications);
modelBuilder.Entity<University>.HasRequired(x => x.Qualification).WithMany(e => e.Universities);

}

この場合、Employee から Qualification へ、および Qualification から大学へのチェーンがあります。だから、私に同じ例外を投げていました。

私が変わったとき、それは私のために働いた

    modelBuilder.Entity<Qualification>().**HasRequired**(x=> x.Employee).WithMany(e => e.Qualifications); 

    modelBuilder.Entity<Qualification>().**HasOptional**(x=> x.Employee).WithMany(e => e.Qualifications);
于 2013-12-16T16:58:24.483 に答える
-2

ASP.NET Core 2.0 と EF Core 2.0 を使用して発生したこの問題に対する私の解決策は、次の手順を実行することでした。

  1. パッケージ管理コンソール (PMC) でコマンドを実行update-databaseしてデータベースを作成します (これにより、「FOREIGN KEY 制約の導入 ... サイクルまたは複数のカスケード パスが発生する可能性があります」というエラーが発生します)。

  2. PMC でコマンドを実行script-migration -Idempotentして、既存のテーブル/制約に関係なく実行できるスクリプトを作成します。

  3. 結果のスクリプトを取得し、検索ON DELETE CASCADEして置き換えますON DELETE NO ACTION

  4. データベースに対して変更された SQL を実行します。

これで、移行は最新の状態になり、カスケード削除は発生しなくなります。

残念ながら、Entity Framework Core 2.0 でこれを行う方法を見つけることができませんでした。

幸運を!

于 2017-11-28T20:37:46.267 に答える