Foreign key constraint may cause cycles or multiple cascade paths?












155















I have a problem when I try to add constraints to my tables. I get the error:




Introducing FOREIGN KEY constraint 'FK74988DB24B3C886' on table 'Employee' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.




My constraint is between a Code table and an employee table. The Code table contains Id, Name, FriendlyName, Type and a Value. The employee has a number of fields that reference codes, so that there can be a reference for each type of code.



I need for the fields to be set to null if the code that is referenced is deleted.



Any ideas how I can do this?










share|improve this question

























  • One of the solution is here

    – IsmailS
    May 7 '12 at 16:40
















155















I have a problem when I try to add constraints to my tables. I get the error:




Introducing FOREIGN KEY constraint 'FK74988DB24B3C886' on table 'Employee' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.




My constraint is between a Code table and an employee table. The Code table contains Id, Name, FriendlyName, Type and a Value. The employee has a number of fields that reference codes, so that there can be a reference for each type of code.



I need for the fields to be set to null if the code that is referenced is deleted.



Any ideas how I can do this?










share|improve this question

























  • One of the solution is here

    – IsmailS
    May 7 '12 at 16:40














155












155








155


20






I have a problem when I try to add constraints to my tables. I get the error:




Introducing FOREIGN KEY constraint 'FK74988DB24B3C886' on table 'Employee' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.




My constraint is between a Code table and an employee table. The Code table contains Id, Name, FriendlyName, Type and a Value. The employee has a number of fields that reference codes, so that there can be a reference for each type of code.



I need for the fields to be set to null if the code that is referenced is deleted.



Any ideas how I can do this?










share|improve this question
















I have a problem when I try to add constraints to my tables. I get the error:




Introducing FOREIGN KEY constraint 'FK74988DB24B3C886' on table 'Employee' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.




My constraint is between a Code table and an employee table. The Code table contains Id, Name, FriendlyName, Type and a Value. The employee has a number of fields that reference codes, so that there can be a reference for each type of code.



I need for the fields to be set to null if the code that is referenced is deleted.



Any ideas how I can do this?







sql sql-server constraints






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Jul 9 '12 at 20:41









Ricardo Altamirano

7,853166199




7,853166199










asked May 12 '09 at 7:47







Christian Nielsen




















  • One of the solution is here

    – IsmailS
    May 7 '12 at 16:40



















  • One of the solution is here

    – IsmailS
    May 7 '12 at 16:40

















One of the solution is here

– IsmailS
May 7 '12 at 16:40





One of the solution is here

– IsmailS
May 7 '12 at 16:40












9 Answers
9






active

oldest

votes


















162














SQL Server does simple counting of cascade paths and, rather than trying to work out whether any cycles actually exist, it assumes the worst and refuses to create the referential actions (CASCADE): you can and should still create the constraints without the referential actions. If you can't alter your design (or doing so would compromise things) then you should consider using triggers as a last resort.



FWIW resolving cascade paths is a complex problem. Other SQL products will simply ignore the problem and allow you to create cycles, in which case it will be a race to see which will overwrite the value last, probably to the ignorance of the designer (e.g. ACE/Jet does this). I understand some SQL products will attempt to resolve simple cases. Fact remains, SQL Server doesn't even try, plays it ultra safe by disallowing more than one path and at least it tells you so.



Microsoft themselves advises the use of triggers instead of FK constraints.






share|improve this answer


























  • I came to the same conclution in the end, and ended up solving it using triggers. Nice to know there is this difference between DBMS and that it is in fact a design decision I am stuck on. Thanks a lot :)

    – Christian Nielsen
    May 12 '09 at 10:37






  • 1





    one thing that i still cannot understand is that, if this "problem" can be solved by using a trigger, then how come that a trigger will not "cause cycles or multiple cascade paths ..." ?

    – armen
    Jul 24 '14 at 10:17






  • 4





    @armen: because your trigger will explicitly supply the logic that the system couldn't implicitly figure out on it's own eg if there are multiple paths for a delete referential action then your trigger code will define which tables are deleted and in which order.

    – onedaywhen
    Aug 5 '14 at 15:22






  • 5





    And also the trigger executes after the first operation completes so there is no race going on.

    – Bon
    Aug 4 '15 at 16:50






  • 2





    @dumbledad: I mean, only use triggers when constraints (maybe on combination) can't get the job done. Constraints are declarative and their implementations are the responsibility of the system. Triggers are procedural code and you must code (and debug) the implementation and endure their disadvantages (worse performance etc).

    – onedaywhen
    Feb 22 '16 at 15:14



















82














A typical situation with multiple cascasing paths will be this:
A master table with two details, let's say "Master" and "Detail1" and "Detail2". Both details are cascade delete. So far no problems. But what if both details have a one-to-many-relation with some other table (say "SomeOtherTable"). SomeOtherTable has a Detail1ID-column AND a Detail2ID-column.



Master { ID, masterfields }

Detail1 { ID, MasterID, detail1fields }

Detail2 { ID, MasterID, detail2fields }

SomeOtherTable {ID, Detail1ID, Detail2ID, someothertablefields }


In other words: some of the records in SomeOtherTable are linked with Detail1-records and some of the records in SomeOtherTable are linked with Detail2 records. Even if it is guaranteed that SomeOtherTable-records never belong to both Details, it is now impossible to make SomeOhterTable's records cascade delete for both details, because there are multiple cascading paths from Master to SomeOtherTable (one via Detail1 and one via Detail2).
Now you may already have understood this. Here is a possible solution:



Master { ID, masterfields }

DetailMain { ID, MasterID }

Detail1 { DetailMainID, detail1fields }

Detail2 { DetailMainID, detail2fields }

SomeOtherTable {ID, DetailMainID, someothertablefields }


All ID fields are key-fields and auto-increment. The crux lies in the DetailMainId fields of the Detail tables. These fields are both key and referential contraint. It is now possible to cascade delete everything by only deleting master-records. The downside is that for each detail1-record AND for each detail2 record, there must also be a DetailMain-record (which is actually created first to get the correct and unique id).






share|improve this answer





















  • 1





    Your comment helped me a lot to understand the problem that I am facing. Thank you! I would prefer turning off the cascade delete for one of the path, then handle delete of other records some other ways(stored procedures; triggers; by code etc). But I keep your solution(grouping in one path) in mind for possible different applications of same problem...

    – freewill
    Feb 14 '14 at 21:39






  • 1





    One up for use of the word crux (and also for explaining)

    – masterwok
    Dec 11 '14 at 4:35











  • Is this better than writing triggers? It seems odd to add an additional table just to get the cascade working.

    – dumbledad
    Feb 2 '16 at 10:04











  • Very good explanation. Thanks.

    – Kamran
    Dec 31 '18 at 17:13



















11














I would point out that (functionally) there's a BIG difference between cycles and/or multiple paths in the SCHEMA and the DATA. While cycles and perhaps multipaths in the DATA could certainly complicated processing and cause performance problems (cost of "properly" handling), the cost of these characteristics in the schema should be close to zero.



Since most apparent cycles in RDBs occur in hierarchical structures (org chart, part, subpart, etc.) it is unfortunate that SQL Server assumes the worst; i.e., schema cycle == data cycle. In fact, if you're using RI constraints you can't actually build a cycle in the data!



I suspect the multipath problem is similar; i.e., multiple paths in the schema don't necessarily imply multiple paths in the data, but I have less experience with the multipath problem.



Of course if SQL Server did allow cycles it'd still be subject to a depth of 32, but that's probably adequate for most cases. (Too bad that's not a database setting however!)



"Instead of Delete" triggers don't work either. The second time a table is visited, the trigger is ignored. So, if you really want to simulate a cascade you'll have to use stored procedures in the presence of cycles. The Instead-of-Delete-Trigger would work for multipath cases however.



Celko suggests a "better" way to represent hierarchies that doesn't introduce cycles, but there are tradeoffs.






share|improve this answer
























  • "if you're using RI constraints you can't actually build a cycle in the data!" -- good point!

    – onedaywhen
    Mar 23 '16 at 17:11



















5














There is an article available in which explains how to perform multiple deletion paths using triggers. Maybe this is useful for complex scenarios.



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






share|improve this answer
























  • Must read article! Thanks

    – Shyamal Parikh
    Dec 10 '15 at 7:47



















3














By the sounds of it you have an OnDelete/OnUpdate action on one of your existing Foreign Keys, that will modify your codes table.



So by creating this Foreign Key, you'd be creating a cyclic problem,



E.g. Updating Employees, causes Codes to changed by an On Update Action, causes Employees to be changed by an On Update Action... etc...



If you post your Table Definitions for both tables, & your Foreign Key/constraint definitions we should be able to tell you where the problem is...






share|improve this answer





















  • 1





    They are fairly long, so I dont think I can post them here, but I would much appreciate your help - dont know if there is some way i can send them to you? Ill try and describe it: The only constraints that exist are from 3 tables that all have fields that reference codes by a simple INT Id key. The problem seems to be that Employee has several fields that reference the code table and that i want them all to cascade to SET NULL. All I need is that when codes are deleted, the references to them should be set to null everywhere.

    – Christian Nielsen
    May 12 '09 at 8:13











  • post them anyway... I don't think anyone here will mind, and the code window will format them properly in a scrolling block :)

    – Eoin Campbell
    May 12 '09 at 8:30



















1














This is because Emplyee might have Collection of other entity say Qualifications and Qualification might have some other collection Universities
e.g.



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;}


}



On DataContext it could be like below



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);


}



in this case there is chain from Employee to Qualification and From Qualification to Universities. So it was throwing same exception to me.



It worked for me when I changed



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


To



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





share|improve this answer

































    1














    Trigger is solution for this problem:



    IF OBJECT_ID('dbo.fktest2', 'U') IS NOT NULL
    drop table fktest2
    IF OBJECT_ID('dbo.fktest1', 'U') IS NOT NULL
    drop table fktest1
    IF EXISTS (SELECT name FROM sysobjects WHERE name = 'fkTest1Trigger' AND type = 'TR')
    DROP TRIGGER dbo.fkTest1Trigger
    go
    create table fktest1 (id int primary key, anQId int identity)
    go
    create table fktest2 (id1 int, id2 int, anQId int identity,
    FOREIGN KEY (id1) REFERENCES fktest1 (id)
    ON DELETE CASCADE
    ON UPDATE CASCADE/*,
    FOREIGN KEY (id2) REFERENCES fktest1 (id) this causes compile error so we have to use triggers
    ON DELETE CASCADE
    ON UPDATE CASCADE*/
    )
    go

    CREATE TRIGGER fkTest1Trigger
    ON fkTest1
    AFTER INSERT, UPDATE, DELETE
    AS
    if @@ROWCOUNT = 0
    return
    set nocount on

    -- This code is replacement for foreign key cascade (auto update of field in destination table when its referenced primary key in source table changes.
    -- Compiler complains only when you use multiple cascased. It throws this compile error:
    -- Rrigger Introducing FOREIGN KEY constraint on table may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION,
    -- or modify other FOREIGN KEY constraints.
    IF ((UPDATE (id) and exists(select 1 from fktest1 A join deleted B on B.anqid = A.anqid where B.id <> A.id)))
    begin
    update fktest2 set id2 = i.id
    from deleted d
    join fktest2 on d.id = fktest2.id2
    join inserted i on i.anqid = d.anqid
    end
    if exists (select 1 from deleted)
    DELETE one FROM fktest2 one LEFT JOIN fktest1 two ON two.id = one.id2 where two.id is null -- drop all from dest table which are not in source table
    GO

    insert into fktest1 (id) values (1)
    insert into fktest1 (id) values (2)
    insert into fktest1 (id) values (3)

    insert into fktest2 (id1, id2) values (1,1)
    insert into fktest2 (id1, id2) values (2,2)
    insert into fktest2 (id1, id2) values (1,3)

    select * from fktest1
    select * from fktest2

    update fktest1 set id=11 where id=1
    update fktest1 set id=22 where id=2
    update fktest1 set id=33 where id=3
    delete from fktest1 where id > 22

    select * from fktest1
    select * from fktest2





    share|improve this answer































      0














      This is an error of type database trigger policies. A trigger is code and can add some intelligences or conditions to a Cascade relation like Cascade Deletion. You may need to specialize the related tables options around this like Turning off CascadeOnDelete:



      protected override void OnModelCreating( DbModelBuilder modelBuilder )
      {
      modelBuilder.Entity<TableName>().HasMany(i => i.Member).WithRequired().WillCascadeOnDelete(false);
      }


      Or Turn off this feature completely:



      modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();





      share|improve this answer































        -2














        My solution to this problem encountered using ASP.NET Core 2.0 and EF Core 2.0 was to perform the following in order:




        1. Run update-database command in Package Management Console (PMC) to create the database (this results in the "Introducing FOREIGN KEY constraint ... may cause cycles or multiple cascade paths." error)


        2. Run script-migration -Idempotent command in PMC to create a script that can be run regardless of the existing tables/constraints


        3. Take the resulting script and find ON DELETE CASCADE and replace with ON DELETE NO ACTION


        4. Execute the modified SQL against the database



        Now, your migrations should be up-to-date and the cascading deletes should not occur.



        Too bad I was not able to find any way to do this in Entity Framework Core 2.0.



        Good luck!






        share|improve this answer
























        • You can change your migration file to do so (without changing sql script), i.e. in your migration file you can set onDelete action to Restrict from Cascade

          – Rushi Soni
          Mar 17 '18 at 11:46











        • It's better to specify this using fluent annotations so that you don't have to remember to do this if you end up deleting and recreating your migrations folder.

          – Allen Wang
          May 1 '18 at 15:08











        • In my experience, the fluent annotations can be used and should be used (I use them) but they are often be quite buggy. Simply specifying them in the code doesn't always work produce the expected result.

          – user1477388
          May 2 '18 at 10:21










        protected by Community May 29 '15 at 7:39



        Thank you for your interest in this question.
        Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).



        Would you like to answer one of these unanswered questions instead?













        9 Answers
        9






        active

        oldest

        votes








        9 Answers
        9






        active

        oldest

        votes









        active

        oldest

        votes






        active

        oldest

        votes









        162














        SQL Server does simple counting of cascade paths and, rather than trying to work out whether any cycles actually exist, it assumes the worst and refuses to create the referential actions (CASCADE): you can and should still create the constraints without the referential actions. If you can't alter your design (or doing so would compromise things) then you should consider using triggers as a last resort.



        FWIW resolving cascade paths is a complex problem. Other SQL products will simply ignore the problem and allow you to create cycles, in which case it will be a race to see which will overwrite the value last, probably to the ignorance of the designer (e.g. ACE/Jet does this). I understand some SQL products will attempt to resolve simple cases. Fact remains, SQL Server doesn't even try, plays it ultra safe by disallowing more than one path and at least it tells you so.



        Microsoft themselves advises the use of triggers instead of FK constraints.






        share|improve this answer


























        • I came to the same conclution in the end, and ended up solving it using triggers. Nice to know there is this difference between DBMS and that it is in fact a design decision I am stuck on. Thanks a lot :)

          – Christian Nielsen
          May 12 '09 at 10:37






        • 1





          one thing that i still cannot understand is that, if this "problem" can be solved by using a trigger, then how come that a trigger will not "cause cycles or multiple cascade paths ..." ?

          – armen
          Jul 24 '14 at 10:17






        • 4





          @armen: because your trigger will explicitly supply the logic that the system couldn't implicitly figure out on it's own eg if there are multiple paths for a delete referential action then your trigger code will define which tables are deleted and in which order.

          – onedaywhen
          Aug 5 '14 at 15:22






        • 5





          And also the trigger executes after the first operation completes so there is no race going on.

          – Bon
          Aug 4 '15 at 16:50






        • 2





          @dumbledad: I mean, only use triggers when constraints (maybe on combination) can't get the job done. Constraints are declarative and their implementations are the responsibility of the system. Triggers are procedural code and you must code (and debug) the implementation and endure their disadvantages (worse performance etc).

          – onedaywhen
          Feb 22 '16 at 15:14
















        162














        SQL Server does simple counting of cascade paths and, rather than trying to work out whether any cycles actually exist, it assumes the worst and refuses to create the referential actions (CASCADE): you can and should still create the constraints without the referential actions. If you can't alter your design (or doing so would compromise things) then you should consider using triggers as a last resort.



        FWIW resolving cascade paths is a complex problem. Other SQL products will simply ignore the problem and allow you to create cycles, in which case it will be a race to see which will overwrite the value last, probably to the ignorance of the designer (e.g. ACE/Jet does this). I understand some SQL products will attempt to resolve simple cases. Fact remains, SQL Server doesn't even try, plays it ultra safe by disallowing more than one path and at least it tells you so.



        Microsoft themselves advises the use of triggers instead of FK constraints.






        share|improve this answer


























        • I came to the same conclution in the end, and ended up solving it using triggers. Nice to know there is this difference between DBMS and that it is in fact a design decision I am stuck on. Thanks a lot :)

          – Christian Nielsen
          May 12 '09 at 10:37






        • 1





          one thing that i still cannot understand is that, if this "problem" can be solved by using a trigger, then how come that a trigger will not "cause cycles or multiple cascade paths ..." ?

          – armen
          Jul 24 '14 at 10:17






        • 4





          @armen: because your trigger will explicitly supply the logic that the system couldn't implicitly figure out on it's own eg if there are multiple paths for a delete referential action then your trigger code will define which tables are deleted and in which order.

          – onedaywhen
          Aug 5 '14 at 15:22






        • 5





          And also the trigger executes after the first operation completes so there is no race going on.

          – Bon
          Aug 4 '15 at 16:50






        • 2





          @dumbledad: I mean, only use triggers when constraints (maybe on combination) can't get the job done. Constraints are declarative and their implementations are the responsibility of the system. Triggers are procedural code and you must code (and debug) the implementation and endure their disadvantages (worse performance etc).

          – onedaywhen
          Feb 22 '16 at 15:14














        162












        162








        162







        SQL Server does simple counting of cascade paths and, rather than trying to work out whether any cycles actually exist, it assumes the worst and refuses to create the referential actions (CASCADE): you can and should still create the constraints without the referential actions. If you can't alter your design (or doing so would compromise things) then you should consider using triggers as a last resort.



        FWIW resolving cascade paths is a complex problem. Other SQL products will simply ignore the problem and allow you to create cycles, in which case it will be a race to see which will overwrite the value last, probably to the ignorance of the designer (e.g. ACE/Jet does this). I understand some SQL products will attempt to resolve simple cases. Fact remains, SQL Server doesn't even try, plays it ultra safe by disallowing more than one path and at least it tells you so.



        Microsoft themselves advises the use of triggers instead of FK constraints.






        share|improve this answer















        SQL Server does simple counting of cascade paths and, rather than trying to work out whether any cycles actually exist, it assumes the worst and refuses to create the referential actions (CASCADE): you can and should still create the constraints without the referential actions. If you can't alter your design (or doing so would compromise things) then you should consider using triggers as a last resort.



        FWIW resolving cascade paths is a complex problem. Other SQL products will simply ignore the problem and allow you to create cycles, in which case it will be a race to see which will overwrite the value last, probably to the ignorance of the designer (e.g. ACE/Jet does this). I understand some SQL products will attempt to resolve simple cases. Fact remains, SQL Server doesn't even try, plays it ultra safe by disallowing more than one path and at least it tells you so.



        Microsoft themselves advises the use of triggers instead of FK constraints.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Feb 1 at 18:03









        Sander

        303513




        303513










        answered May 12 '09 at 10:03









        onedaywhenonedaywhen

        43.7k1079121




        43.7k1079121













        • I came to the same conclution in the end, and ended up solving it using triggers. Nice to know there is this difference between DBMS and that it is in fact a design decision I am stuck on. Thanks a lot :)

          – Christian Nielsen
          May 12 '09 at 10:37






        • 1





          one thing that i still cannot understand is that, if this "problem" can be solved by using a trigger, then how come that a trigger will not "cause cycles or multiple cascade paths ..." ?

          – armen
          Jul 24 '14 at 10:17






        • 4





          @armen: because your trigger will explicitly supply the logic that the system couldn't implicitly figure out on it's own eg if there are multiple paths for a delete referential action then your trigger code will define which tables are deleted and in which order.

          – onedaywhen
          Aug 5 '14 at 15:22






        • 5





          And also the trigger executes after the first operation completes so there is no race going on.

          – Bon
          Aug 4 '15 at 16:50






        • 2





          @dumbledad: I mean, only use triggers when constraints (maybe on combination) can't get the job done. Constraints are declarative and their implementations are the responsibility of the system. Triggers are procedural code and you must code (and debug) the implementation and endure their disadvantages (worse performance etc).

          – onedaywhen
          Feb 22 '16 at 15:14



















        • I came to the same conclution in the end, and ended up solving it using triggers. Nice to know there is this difference between DBMS and that it is in fact a design decision I am stuck on. Thanks a lot :)

          – Christian Nielsen
          May 12 '09 at 10:37






        • 1





          one thing that i still cannot understand is that, if this "problem" can be solved by using a trigger, then how come that a trigger will not "cause cycles or multiple cascade paths ..." ?

          – armen
          Jul 24 '14 at 10:17






        • 4





          @armen: because your trigger will explicitly supply the logic that the system couldn't implicitly figure out on it's own eg if there are multiple paths for a delete referential action then your trigger code will define which tables are deleted and in which order.

          – onedaywhen
          Aug 5 '14 at 15:22






        • 5





          And also the trigger executes after the first operation completes so there is no race going on.

          – Bon
          Aug 4 '15 at 16:50






        • 2





          @dumbledad: I mean, only use triggers when constraints (maybe on combination) can't get the job done. Constraints are declarative and their implementations are the responsibility of the system. Triggers are procedural code and you must code (and debug) the implementation and endure their disadvantages (worse performance etc).

          – onedaywhen
          Feb 22 '16 at 15:14

















        I came to the same conclution in the end, and ended up solving it using triggers. Nice to know there is this difference between DBMS and that it is in fact a design decision I am stuck on. Thanks a lot :)

        – Christian Nielsen
        May 12 '09 at 10:37





        I came to the same conclution in the end, and ended up solving it using triggers. Nice to know there is this difference between DBMS and that it is in fact a design decision I am stuck on. Thanks a lot :)

        – Christian Nielsen
        May 12 '09 at 10:37




        1




        1





        one thing that i still cannot understand is that, if this "problem" can be solved by using a trigger, then how come that a trigger will not "cause cycles or multiple cascade paths ..." ?

        – armen
        Jul 24 '14 at 10:17





        one thing that i still cannot understand is that, if this "problem" can be solved by using a trigger, then how come that a trigger will not "cause cycles or multiple cascade paths ..." ?

        – armen
        Jul 24 '14 at 10:17




        4




        4





        @armen: because your trigger will explicitly supply the logic that the system couldn't implicitly figure out on it's own eg if there are multiple paths for a delete referential action then your trigger code will define which tables are deleted and in which order.

        – onedaywhen
        Aug 5 '14 at 15:22





        @armen: because your trigger will explicitly supply the logic that the system couldn't implicitly figure out on it's own eg if there are multiple paths for a delete referential action then your trigger code will define which tables are deleted and in which order.

        – onedaywhen
        Aug 5 '14 at 15:22




        5




        5





        And also the trigger executes after the first operation completes so there is no race going on.

        – Bon
        Aug 4 '15 at 16:50





        And also the trigger executes after the first operation completes so there is no race going on.

        – Bon
        Aug 4 '15 at 16:50




        2




        2





        @dumbledad: I mean, only use triggers when constraints (maybe on combination) can't get the job done. Constraints are declarative and their implementations are the responsibility of the system. Triggers are procedural code and you must code (and debug) the implementation and endure their disadvantages (worse performance etc).

        – onedaywhen
        Feb 22 '16 at 15:14





        @dumbledad: I mean, only use triggers when constraints (maybe on combination) can't get the job done. Constraints are declarative and their implementations are the responsibility of the system. Triggers are procedural code and you must code (and debug) the implementation and endure their disadvantages (worse performance etc).

        – onedaywhen
        Feb 22 '16 at 15:14













        82














        A typical situation with multiple cascasing paths will be this:
        A master table with two details, let's say "Master" and "Detail1" and "Detail2". Both details are cascade delete. So far no problems. But what if both details have a one-to-many-relation with some other table (say "SomeOtherTable"). SomeOtherTable has a Detail1ID-column AND a Detail2ID-column.



        Master { ID, masterfields }

        Detail1 { ID, MasterID, detail1fields }

        Detail2 { ID, MasterID, detail2fields }

        SomeOtherTable {ID, Detail1ID, Detail2ID, someothertablefields }


        In other words: some of the records in SomeOtherTable are linked with Detail1-records and some of the records in SomeOtherTable are linked with Detail2 records. Even if it is guaranteed that SomeOtherTable-records never belong to both Details, it is now impossible to make SomeOhterTable's records cascade delete for both details, because there are multiple cascading paths from Master to SomeOtherTable (one via Detail1 and one via Detail2).
        Now you may already have understood this. Here is a possible solution:



        Master { ID, masterfields }

        DetailMain { ID, MasterID }

        Detail1 { DetailMainID, detail1fields }

        Detail2 { DetailMainID, detail2fields }

        SomeOtherTable {ID, DetailMainID, someothertablefields }


        All ID fields are key-fields and auto-increment. The crux lies in the DetailMainId fields of the Detail tables. These fields are both key and referential contraint. It is now possible to cascade delete everything by only deleting master-records. The downside is that for each detail1-record AND for each detail2 record, there must also be a DetailMain-record (which is actually created first to get the correct and unique id).






        share|improve this answer





















        • 1





          Your comment helped me a lot to understand the problem that I am facing. Thank you! I would prefer turning off the cascade delete for one of the path, then handle delete of other records some other ways(stored procedures; triggers; by code etc). But I keep your solution(grouping in one path) in mind for possible different applications of same problem...

          – freewill
          Feb 14 '14 at 21:39






        • 1





          One up for use of the word crux (and also for explaining)

          – masterwok
          Dec 11 '14 at 4:35











        • Is this better than writing triggers? It seems odd to add an additional table just to get the cascade working.

          – dumbledad
          Feb 2 '16 at 10:04











        • Very good explanation. Thanks.

          – Kamran
          Dec 31 '18 at 17:13
















        82














        A typical situation with multiple cascasing paths will be this:
        A master table with two details, let's say "Master" and "Detail1" and "Detail2". Both details are cascade delete. So far no problems. But what if both details have a one-to-many-relation with some other table (say "SomeOtherTable"). SomeOtherTable has a Detail1ID-column AND a Detail2ID-column.



        Master { ID, masterfields }

        Detail1 { ID, MasterID, detail1fields }

        Detail2 { ID, MasterID, detail2fields }

        SomeOtherTable {ID, Detail1ID, Detail2ID, someothertablefields }


        In other words: some of the records in SomeOtherTable are linked with Detail1-records and some of the records in SomeOtherTable are linked with Detail2 records. Even if it is guaranteed that SomeOtherTable-records never belong to both Details, it is now impossible to make SomeOhterTable's records cascade delete for both details, because there are multiple cascading paths from Master to SomeOtherTable (one via Detail1 and one via Detail2).
        Now you may already have understood this. Here is a possible solution:



        Master { ID, masterfields }

        DetailMain { ID, MasterID }

        Detail1 { DetailMainID, detail1fields }

        Detail2 { DetailMainID, detail2fields }

        SomeOtherTable {ID, DetailMainID, someothertablefields }


        All ID fields are key-fields and auto-increment. The crux lies in the DetailMainId fields of the Detail tables. These fields are both key and referential contraint. It is now possible to cascade delete everything by only deleting master-records. The downside is that for each detail1-record AND for each detail2 record, there must also be a DetailMain-record (which is actually created first to get the correct and unique id).






        share|improve this answer





















        • 1





          Your comment helped me a lot to understand the problem that I am facing. Thank you! I would prefer turning off the cascade delete for one of the path, then handle delete of other records some other ways(stored procedures; triggers; by code etc). But I keep your solution(grouping in one path) in mind for possible different applications of same problem...

          – freewill
          Feb 14 '14 at 21:39






        • 1





          One up for use of the word crux (and also for explaining)

          – masterwok
          Dec 11 '14 at 4:35











        • Is this better than writing triggers? It seems odd to add an additional table just to get the cascade working.

          – dumbledad
          Feb 2 '16 at 10:04











        • Very good explanation. Thanks.

          – Kamran
          Dec 31 '18 at 17:13














        82












        82








        82







        A typical situation with multiple cascasing paths will be this:
        A master table with two details, let's say "Master" and "Detail1" and "Detail2". Both details are cascade delete. So far no problems. But what if both details have a one-to-many-relation with some other table (say "SomeOtherTable"). SomeOtherTable has a Detail1ID-column AND a Detail2ID-column.



        Master { ID, masterfields }

        Detail1 { ID, MasterID, detail1fields }

        Detail2 { ID, MasterID, detail2fields }

        SomeOtherTable {ID, Detail1ID, Detail2ID, someothertablefields }


        In other words: some of the records in SomeOtherTable are linked with Detail1-records and some of the records in SomeOtherTable are linked with Detail2 records. Even if it is guaranteed that SomeOtherTable-records never belong to both Details, it is now impossible to make SomeOhterTable's records cascade delete for both details, because there are multiple cascading paths from Master to SomeOtherTable (one via Detail1 and one via Detail2).
        Now you may already have understood this. Here is a possible solution:



        Master { ID, masterfields }

        DetailMain { ID, MasterID }

        Detail1 { DetailMainID, detail1fields }

        Detail2 { DetailMainID, detail2fields }

        SomeOtherTable {ID, DetailMainID, someothertablefields }


        All ID fields are key-fields and auto-increment. The crux lies in the DetailMainId fields of the Detail tables. These fields are both key and referential contraint. It is now possible to cascade delete everything by only deleting master-records. The downside is that for each detail1-record AND for each detail2 record, there must also be a DetailMain-record (which is actually created first to get the correct and unique id).






        share|improve this answer















        A typical situation with multiple cascasing paths will be this:
        A master table with two details, let's say "Master" and "Detail1" and "Detail2". Both details are cascade delete. So far no problems. But what if both details have a one-to-many-relation with some other table (say "SomeOtherTable"). SomeOtherTable has a Detail1ID-column AND a Detail2ID-column.



        Master { ID, masterfields }

        Detail1 { ID, MasterID, detail1fields }

        Detail2 { ID, MasterID, detail2fields }

        SomeOtherTable {ID, Detail1ID, Detail2ID, someothertablefields }


        In other words: some of the records in SomeOtherTable are linked with Detail1-records and some of the records in SomeOtherTable are linked with Detail2 records. Even if it is guaranteed that SomeOtherTable-records never belong to both Details, it is now impossible to make SomeOhterTable's records cascade delete for both details, because there are multiple cascading paths from Master to SomeOtherTable (one via Detail1 and one via Detail2).
        Now you may already have understood this. Here is a possible solution:



        Master { ID, masterfields }

        DetailMain { ID, MasterID }

        Detail1 { DetailMainID, detail1fields }

        Detail2 { DetailMainID, detail2fields }

        SomeOtherTable {ID, DetailMainID, someothertablefields }


        All ID fields are key-fields and auto-increment. The crux lies in the DetailMainId fields of the Detail tables. These fields are both key and referential contraint. It is now possible to cascade delete everything by only deleting master-records. The downside is that for each detail1-record AND for each detail2 record, there must also be a DetailMain-record (which is actually created first to get the correct and unique id).







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Mar 27 '12 at 12:23









        Chuck Norris

        12.5k1173115




        12.5k1173115










        answered Aug 23 '10 at 13:55









        hans rieseboshans riesebos

        82962




        82962








        • 1





          Your comment helped me a lot to understand the problem that I am facing. Thank you! I would prefer turning off the cascade delete for one of the path, then handle delete of other records some other ways(stored procedures; triggers; by code etc). But I keep your solution(grouping in one path) in mind for possible different applications of same problem...

          – freewill
          Feb 14 '14 at 21:39






        • 1





          One up for use of the word crux (and also for explaining)

          – masterwok
          Dec 11 '14 at 4:35











        • Is this better than writing triggers? It seems odd to add an additional table just to get the cascade working.

          – dumbledad
          Feb 2 '16 at 10:04











        • Very good explanation. Thanks.

          – Kamran
          Dec 31 '18 at 17:13














        • 1





          Your comment helped me a lot to understand the problem that I am facing. Thank you! I would prefer turning off the cascade delete for one of the path, then handle delete of other records some other ways(stored procedures; triggers; by code etc). But I keep your solution(grouping in one path) in mind for possible different applications of same problem...

          – freewill
          Feb 14 '14 at 21:39






        • 1





          One up for use of the word crux (and also for explaining)

          – masterwok
          Dec 11 '14 at 4:35











        • Is this better than writing triggers? It seems odd to add an additional table just to get the cascade working.

          – dumbledad
          Feb 2 '16 at 10:04











        • Very good explanation. Thanks.

          – Kamran
          Dec 31 '18 at 17:13








        1




        1





        Your comment helped me a lot to understand the problem that I am facing. Thank you! I would prefer turning off the cascade delete for one of the path, then handle delete of other records some other ways(stored procedures; triggers; by code etc). But I keep your solution(grouping in one path) in mind for possible different applications of same problem...

        – freewill
        Feb 14 '14 at 21:39





        Your comment helped me a lot to understand the problem that I am facing. Thank you! I would prefer turning off the cascade delete for one of the path, then handle delete of other records some other ways(stored procedures; triggers; by code etc). But I keep your solution(grouping in one path) in mind for possible different applications of same problem...

        – freewill
        Feb 14 '14 at 21:39




        1




        1





        One up for use of the word crux (and also for explaining)

        – masterwok
        Dec 11 '14 at 4:35





        One up for use of the word crux (and also for explaining)

        – masterwok
        Dec 11 '14 at 4:35













        Is this better than writing triggers? It seems odd to add an additional table just to get the cascade working.

        – dumbledad
        Feb 2 '16 at 10:04





        Is this better than writing triggers? It seems odd to add an additional table just to get the cascade working.

        – dumbledad
        Feb 2 '16 at 10:04













        Very good explanation. Thanks.

        – Kamran
        Dec 31 '18 at 17:13





        Very good explanation. Thanks.

        – Kamran
        Dec 31 '18 at 17:13











        11














        I would point out that (functionally) there's a BIG difference between cycles and/or multiple paths in the SCHEMA and the DATA. While cycles and perhaps multipaths in the DATA could certainly complicated processing and cause performance problems (cost of "properly" handling), the cost of these characteristics in the schema should be close to zero.



        Since most apparent cycles in RDBs occur in hierarchical structures (org chart, part, subpart, etc.) it is unfortunate that SQL Server assumes the worst; i.e., schema cycle == data cycle. In fact, if you're using RI constraints you can't actually build a cycle in the data!



        I suspect the multipath problem is similar; i.e., multiple paths in the schema don't necessarily imply multiple paths in the data, but I have less experience with the multipath problem.



        Of course if SQL Server did allow cycles it'd still be subject to a depth of 32, but that's probably adequate for most cases. (Too bad that's not a database setting however!)



        "Instead of Delete" triggers don't work either. The second time a table is visited, the trigger is ignored. So, if you really want to simulate a cascade you'll have to use stored procedures in the presence of cycles. The Instead-of-Delete-Trigger would work for multipath cases however.



        Celko suggests a "better" way to represent hierarchies that doesn't introduce cycles, but there are tradeoffs.






        share|improve this answer
























        • "if you're using RI constraints you can't actually build a cycle in the data!" -- good point!

          – onedaywhen
          Mar 23 '16 at 17:11
















        11














        I would point out that (functionally) there's a BIG difference between cycles and/or multiple paths in the SCHEMA and the DATA. While cycles and perhaps multipaths in the DATA could certainly complicated processing and cause performance problems (cost of "properly" handling), the cost of these characteristics in the schema should be close to zero.



        Since most apparent cycles in RDBs occur in hierarchical structures (org chart, part, subpart, etc.) it is unfortunate that SQL Server assumes the worst; i.e., schema cycle == data cycle. In fact, if you're using RI constraints you can't actually build a cycle in the data!



        I suspect the multipath problem is similar; i.e., multiple paths in the schema don't necessarily imply multiple paths in the data, but I have less experience with the multipath problem.



        Of course if SQL Server did allow cycles it'd still be subject to a depth of 32, but that's probably adequate for most cases. (Too bad that's not a database setting however!)



        "Instead of Delete" triggers don't work either. The second time a table is visited, the trigger is ignored. So, if you really want to simulate a cascade you'll have to use stored procedures in the presence of cycles. The Instead-of-Delete-Trigger would work for multipath cases however.



        Celko suggests a "better" way to represent hierarchies that doesn't introduce cycles, but there are tradeoffs.






        share|improve this answer
























        • "if you're using RI constraints you can't actually build a cycle in the data!" -- good point!

          – onedaywhen
          Mar 23 '16 at 17:11














        11












        11








        11







        I would point out that (functionally) there's a BIG difference between cycles and/or multiple paths in the SCHEMA and the DATA. While cycles and perhaps multipaths in the DATA could certainly complicated processing and cause performance problems (cost of "properly" handling), the cost of these characteristics in the schema should be close to zero.



        Since most apparent cycles in RDBs occur in hierarchical structures (org chart, part, subpart, etc.) it is unfortunate that SQL Server assumes the worst; i.e., schema cycle == data cycle. In fact, if you're using RI constraints you can't actually build a cycle in the data!



        I suspect the multipath problem is similar; i.e., multiple paths in the schema don't necessarily imply multiple paths in the data, but I have less experience with the multipath problem.



        Of course if SQL Server did allow cycles it'd still be subject to a depth of 32, but that's probably adequate for most cases. (Too bad that's not a database setting however!)



        "Instead of Delete" triggers don't work either. The second time a table is visited, the trigger is ignored. So, if you really want to simulate a cascade you'll have to use stored procedures in the presence of cycles. The Instead-of-Delete-Trigger would work for multipath cases however.



        Celko suggests a "better" way to represent hierarchies that doesn't introduce cycles, but there are tradeoffs.






        share|improve this answer













        I would point out that (functionally) there's a BIG difference between cycles and/or multiple paths in the SCHEMA and the DATA. While cycles and perhaps multipaths in the DATA could certainly complicated processing and cause performance problems (cost of "properly" handling), the cost of these characteristics in the schema should be close to zero.



        Since most apparent cycles in RDBs occur in hierarchical structures (org chart, part, subpart, etc.) it is unfortunate that SQL Server assumes the worst; i.e., schema cycle == data cycle. In fact, if you're using RI constraints you can't actually build a cycle in the data!



        I suspect the multipath problem is similar; i.e., multiple paths in the schema don't necessarily imply multiple paths in the data, but I have less experience with the multipath problem.



        Of course if SQL Server did allow cycles it'd still be subject to a depth of 32, but that's probably adequate for most cases. (Too bad that's not a database setting however!)



        "Instead of Delete" triggers don't work either. The second time a table is visited, the trigger is ignored. So, if you really want to simulate a cascade you'll have to use stored procedures in the presence of cycles. The Instead-of-Delete-Trigger would work for multipath cases however.



        Celko suggests a "better" way to represent hierarchies that doesn't introduce cycles, but there are tradeoffs.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered May 4 '10 at 19:29









        Bill CohaganBill Cohagan

        17929




        17929













        • "if you're using RI constraints you can't actually build a cycle in the data!" -- good point!

          – onedaywhen
          Mar 23 '16 at 17:11



















        • "if you're using RI constraints you can't actually build a cycle in the data!" -- good point!

          – onedaywhen
          Mar 23 '16 at 17:11

















        "if you're using RI constraints you can't actually build a cycle in the data!" -- good point!

        – onedaywhen
        Mar 23 '16 at 17:11





        "if you're using RI constraints you can't actually build a cycle in the data!" -- good point!

        – onedaywhen
        Mar 23 '16 at 17:11











        5














        There is an article available in which explains how to perform multiple deletion paths using triggers. Maybe this is useful for complex scenarios.



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






        share|improve this answer
























        • Must read article! Thanks

          – Shyamal Parikh
          Dec 10 '15 at 7:47
















        5














        There is an article available in which explains how to perform multiple deletion paths using triggers. Maybe this is useful for complex scenarios.



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






        share|improve this answer
























        • Must read article! Thanks

          – Shyamal Parikh
          Dec 10 '15 at 7:47














        5












        5








        5







        There is an article available in which explains how to perform multiple deletion paths using triggers. Maybe this is useful for complex scenarios.



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






        share|improve this answer













        There is an article available in which explains how to perform multiple deletion paths using triggers. Maybe this is useful for complex scenarios.



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







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered May 28 '15 at 14:38









        JavierJavier

        1,1501935




        1,1501935













        • Must read article! Thanks

          – Shyamal Parikh
          Dec 10 '15 at 7:47



















        • Must read article! Thanks

          – Shyamal Parikh
          Dec 10 '15 at 7:47

















        Must read article! Thanks

        – Shyamal Parikh
        Dec 10 '15 at 7:47





        Must read article! Thanks

        – Shyamal Parikh
        Dec 10 '15 at 7:47











        3














        By the sounds of it you have an OnDelete/OnUpdate action on one of your existing Foreign Keys, that will modify your codes table.



        So by creating this Foreign Key, you'd be creating a cyclic problem,



        E.g. Updating Employees, causes Codes to changed by an On Update Action, causes Employees to be changed by an On Update Action... etc...



        If you post your Table Definitions for both tables, & your Foreign Key/constraint definitions we should be able to tell you where the problem is...






        share|improve this answer





















        • 1





          They are fairly long, so I dont think I can post them here, but I would much appreciate your help - dont know if there is some way i can send them to you? Ill try and describe it: The only constraints that exist are from 3 tables that all have fields that reference codes by a simple INT Id key. The problem seems to be that Employee has several fields that reference the code table and that i want them all to cascade to SET NULL. All I need is that when codes are deleted, the references to them should be set to null everywhere.

          – Christian Nielsen
          May 12 '09 at 8:13











        • post them anyway... I don't think anyone here will mind, and the code window will format them properly in a scrolling block :)

          – Eoin Campbell
          May 12 '09 at 8:30
















        3














        By the sounds of it you have an OnDelete/OnUpdate action on one of your existing Foreign Keys, that will modify your codes table.



        So by creating this Foreign Key, you'd be creating a cyclic problem,



        E.g. Updating Employees, causes Codes to changed by an On Update Action, causes Employees to be changed by an On Update Action... etc...



        If you post your Table Definitions for both tables, & your Foreign Key/constraint definitions we should be able to tell you where the problem is...






        share|improve this answer





















        • 1





          They are fairly long, so I dont think I can post them here, but I would much appreciate your help - dont know if there is some way i can send them to you? Ill try and describe it: The only constraints that exist are from 3 tables that all have fields that reference codes by a simple INT Id key. The problem seems to be that Employee has several fields that reference the code table and that i want them all to cascade to SET NULL. All I need is that when codes are deleted, the references to them should be set to null everywhere.

          – Christian Nielsen
          May 12 '09 at 8:13











        • post them anyway... I don't think anyone here will mind, and the code window will format them properly in a scrolling block :)

          – Eoin Campbell
          May 12 '09 at 8:30














        3












        3








        3







        By the sounds of it you have an OnDelete/OnUpdate action on one of your existing Foreign Keys, that will modify your codes table.



        So by creating this Foreign Key, you'd be creating a cyclic problem,



        E.g. Updating Employees, causes Codes to changed by an On Update Action, causes Employees to be changed by an On Update Action... etc...



        If you post your Table Definitions for both tables, & your Foreign Key/constraint definitions we should be able to tell you where the problem is...






        share|improve this answer















        By the sounds of it you have an OnDelete/OnUpdate action on one of your existing Foreign Keys, that will modify your codes table.



        So by creating this Foreign Key, you'd be creating a cyclic problem,



        E.g. Updating Employees, causes Codes to changed by an On Update Action, causes Employees to be changed by an On Update Action... etc...



        If you post your Table Definitions for both tables, & your Foreign Key/constraint definitions we should be able to tell you where the problem is...







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Oct 2 '18 at 8:50









        Mihai Alexandru-Ionut

        30.4k64072




        30.4k64072










        answered May 12 '09 at 7:52









        Eoin CampbellEoin Campbell

        33.7k1787141




        33.7k1787141








        • 1





          They are fairly long, so I dont think I can post them here, but I would much appreciate your help - dont know if there is some way i can send them to you? Ill try and describe it: The only constraints that exist are from 3 tables that all have fields that reference codes by a simple INT Id key. The problem seems to be that Employee has several fields that reference the code table and that i want them all to cascade to SET NULL. All I need is that when codes are deleted, the references to them should be set to null everywhere.

          – Christian Nielsen
          May 12 '09 at 8:13











        • post them anyway... I don't think anyone here will mind, and the code window will format them properly in a scrolling block :)

          – Eoin Campbell
          May 12 '09 at 8:30














        • 1





          They are fairly long, so I dont think I can post them here, but I would much appreciate your help - dont know if there is some way i can send them to you? Ill try and describe it: The only constraints that exist are from 3 tables that all have fields that reference codes by a simple INT Id key. The problem seems to be that Employee has several fields that reference the code table and that i want them all to cascade to SET NULL. All I need is that when codes are deleted, the references to them should be set to null everywhere.

          – Christian Nielsen
          May 12 '09 at 8:13











        • post them anyway... I don't think anyone here will mind, and the code window will format them properly in a scrolling block :)

          – Eoin Campbell
          May 12 '09 at 8:30








        1




        1





        They are fairly long, so I dont think I can post them here, but I would much appreciate your help - dont know if there is some way i can send them to you? Ill try and describe it: The only constraints that exist are from 3 tables that all have fields that reference codes by a simple INT Id key. The problem seems to be that Employee has several fields that reference the code table and that i want them all to cascade to SET NULL. All I need is that when codes are deleted, the references to them should be set to null everywhere.

        – Christian Nielsen
        May 12 '09 at 8:13





        They are fairly long, so I dont think I can post them here, but I would much appreciate your help - dont know if there is some way i can send them to you? Ill try and describe it: The only constraints that exist are from 3 tables that all have fields that reference codes by a simple INT Id key. The problem seems to be that Employee has several fields that reference the code table and that i want them all to cascade to SET NULL. All I need is that when codes are deleted, the references to them should be set to null everywhere.

        – Christian Nielsen
        May 12 '09 at 8:13













        post them anyway... I don't think anyone here will mind, and the code window will format them properly in a scrolling block :)

        – Eoin Campbell
        May 12 '09 at 8:30





        post them anyway... I don't think anyone here will mind, and the code window will format them properly in a scrolling block :)

        – Eoin Campbell
        May 12 '09 at 8:30











        1














        This is because Emplyee might have Collection of other entity say Qualifications and Qualification might have some other collection Universities
        e.g.



        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;}


        }



        On DataContext it could be like below



        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);


        }



        in this case there is chain from Employee to Qualification and From Qualification to Universities. So it was throwing same exception to me.



        It worked for me when I changed



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


        To



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





        share|improve this answer






























          1














          This is because Emplyee might have Collection of other entity say Qualifications and Qualification might have some other collection Universities
          e.g.



          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;}


          }



          On DataContext it could be like below



          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);


          }



          in this case there is chain from Employee to Qualification and From Qualification to Universities. So it was throwing same exception to me.



          It worked for me when I changed



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


          To



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





          share|improve this answer




























            1












            1








            1







            This is because Emplyee might have Collection of other entity say Qualifications and Qualification might have some other collection Universities
            e.g.



            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;}


            }



            On DataContext it could be like below



            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);


            }



            in this case there is chain from Employee to Qualification and From Qualification to Universities. So it was throwing same exception to me.



            It worked for me when I changed



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


            To



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





            share|improve this answer















            This is because Emplyee might have Collection of other entity say Qualifications and Qualification might have some other collection Universities
            e.g.



            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;}


            }



            On DataContext it could be like below



            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);


            }



            in this case there is chain from Employee to Qualification and From Qualification to Universities. So it was throwing same exception to me.



            It worked for me when I changed



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


            To



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






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Dec 16 '13 at 17:11

























            answered Dec 16 '13 at 16:58









            RAJRAJ

            854913




            854913























                1














                Trigger is solution for this problem:



                IF OBJECT_ID('dbo.fktest2', 'U') IS NOT NULL
                drop table fktest2
                IF OBJECT_ID('dbo.fktest1', 'U') IS NOT NULL
                drop table fktest1
                IF EXISTS (SELECT name FROM sysobjects WHERE name = 'fkTest1Trigger' AND type = 'TR')
                DROP TRIGGER dbo.fkTest1Trigger
                go
                create table fktest1 (id int primary key, anQId int identity)
                go
                create table fktest2 (id1 int, id2 int, anQId int identity,
                FOREIGN KEY (id1) REFERENCES fktest1 (id)
                ON DELETE CASCADE
                ON UPDATE CASCADE/*,
                FOREIGN KEY (id2) REFERENCES fktest1 (id) this causes compile error so we have to use triggers
                ON DELETE CASCADE
                ON UPDATE CASCADE*/
                )
                go

                CREATE TRIGGER fkTest1Trigger
                ON fkTest1
                AFTER INSERT, UPDATE, DELETE
                AS
                if @@ROWCOUNT = 0
                return
                set nocount on

                -- This code is replacement for foreign key cascade (auto update of field in destination table when its referenced primary key in source table changes.
                -- Compiler complains only when you use multiple cascased. It throws this compile error:
                -- Rrigger Introducing FOREIGN KEY constraint on table may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION,
                -- or modify other FOREIGN KEY constraints.
                IF ((UPDATE (id) and exists(select 1 from fktest1 A join deleted B on B.anqid = A.anqid where B.id <> A.id)))
                begin
                update fktest2 set id2 = i.id
                from deleted d
                join fktest2 on d.id = fktest2.id2
                join inserted i on i.anqid = d.anqid
                end
                if exists (select 1 from deleted)
                DELETE one FROM fktest2 one LEFT JOIN fktest1 two ON two.id = one.id2 where two.id is null -- drop all from dest table which are not in source table
                GO

                insert into fktest1 (id) values (1)
                insert into fktest1 (id) values (2)
                insert into fktest1 (id) values (3)

                insert into fktest2 (id1, id2) values (1,1)
                insert into fktest2 (id1, id2) values (2,2)
                insert into fktest2 (id1, id2) values (1,3)

                select * from fktest1
                select * from fktest2

                update fktest1 set id=11 where id=1
                update fktest1 set id=22 where id=2
                update fktest1 set id=33 where id=3
                delete from fktest1 where id > 22

                select * from fktest1
                select * from fktest2





                share|improve this answer




























                  1














                  Trigger is solution for this problem:



                  IF OBJECT_ID('dbo.fktest2', 'U') IS NOT NULL
                  drop table fktest2
                  IF OBJECT_ID('dbo.fktest1', 'U') IS NOT NULL
                  drop table fktest1
                  IF EXISTS (SELECT name FROM sysobjects WHERE name = 'fkTest1Trigger' AND type = 'TR')
                  DROP TRIGGER dbo.fkTest1Trigger
                  go
                  create table fktest1 (id int primary key, anQId int identity)
                  go
                  create table fktest2 (id1 int, id2 int, anQId int identity,
                  FOREIGN KEY (id1) REFERENCES fktest1 (id)
                  ON DELETE CASCADE
                  ON UPDATE CASCADE/*,
                  FOREIGN KEY (id2) REFERENCES fktest1 (id) this causes compile error so we have to use triggers
                  ON DELETE CASCADE
                  ON UPDATE CASCADE*/
                  )
                  go

                  CREATE TRIGGER fkTest1Trigger
                  ON fkTest1
                  AFTER INSERT, UPDATE, DELETE
                  AS
                  if @@ROWCOUNT = 0
                  return
                  set nocount on

                  -- This code is replacement for foreign key cascade (auto update of field in destination table when its referenced primary key in source table changes.
                  -- Compiler complains only when you use multiple cascased. It throws this compile error:
                  -- Rrigger Introducing FOREIGN KEY constraint on table may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION,
                  -- or modify other FOREIGN KEY constraints.
                  IF ((UPDATE (id) and exists(select 1 from fktest1 A join deleted B on B.anqid = A.anqid where B.id <> A.id)))
                  begin
                  update fktest2 set id2 = i.id
                  from deleted d
                  join fktest2 on d.id = fktest2.id2
                  join inserted i on i.anqid = d.anqid
                  end
                  if exists (select 1 from deleted)
                  DELETE one FROM fktest2 one LEFT JOIN fktest1 two ON two.id = one.id2 where two.id is null -- drop all from dest table which are not in source table
                  GO

                  insert into fktest1 (id) values (1)
                  insert into fktest1 (id) values (2)
                  insert into fktest1 (id) values (3)

                  insert into fktest2 (id1, id2) values (1,1)
                  insert into fktest2 (id1, id2) values (2,2)
                  insert into fktest2 (id1, id2) values (1,3)

                  select * from fktest1
                  select * from fktest2

                  update fktest1 set id=11 where id=1
                  update fktest1 set id=22 where id=2
                  update fktest1 set id=33 where id=3
                  delete from fktest1 where id > 22

                  select * from fktest1
                  select * from fktest2





                  share|improve this answer


























                    1












                    1








                    1







                    Trigger is solution for this problem:



                    IF OBJECT_ID('dbo.fktest2', 'U') IS NOT NULL
                    drop table fktest2
                    IF OBJECT_ID('dbo.fktest1', 'U') IS NOT NULL
                    drop table fktest1
                    IF EXISTS (SELECT name FROM sysobjects WHERE name = 'fkTest1Trigger' AND type = 'TR')
                    DROP TRIGGER dbo.fkTest1Trigger
                    go
                    create table fktest1 (id int primary key, anQId int identity)
                    go
                    create table fktest2 (id1 int, id2 int, anQId int identity,
                    FOREIGN KEY (id1) REFERENCES fktest1 (id)
                    ON DELETE CASCADE
                    ON UPDATE CASCADE/*,
                    FOREIGN KEY (id2) REFERENCES fktest1 (id) this causes compile error so we have to use triggers
                    ON DELETE CASCADE
                    ON UPDATE CASCADE*/
                    )
                    go

                    CREATE TRIGGER fkTest1Trigger
                    ON fkTest1
                    AFTER INSERT, UPDATE, DELETE
                    AS
                    if @@ROWCOUNT = 0
                    return
                    set nocount on

                    -- This code is replacement for foreign key cascade (auto update of field in destination table when its referenced primary key in source table changes.
                    -- Compiler complains only when you use multiple cascased. It throws this compile error:
                    -- Rrigger Introducing FOREIGN KEY constraint on table may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION,
                    -- or modify other FOREIGN KEY constraints.
                    IF ((UPDATE (id) and exists(select 1 from fktest1 A join deleted B on B.anqid = A.anqid where B.id <> A.id)))
                    begin
                    update fktest2 set id2 = i.id
                    from deleted d
                    join fktest2 on d.id = fktest2.id2
                    join inserted i on i.anqid = d.anqid
                    end
                    if exists (select 1 from deleted)
                    DELETE one FROM fktest2 one LEFT JOIN fktest1 two ON two.id = one.id2 where two.id is null -- drop all from dest table which are not in source table
                    GO

                    insert into fktest1 (id) values (1)
                    insert into fktest1 (id) values (2)
                    insert into fktest1 (id) values (3)

                    insert into fktest2 (id1, id2) values (1,1)
                    insert into fktest2 (id1, id2) values (2,2)
                    insert into fktest2 (id1, id2) values (1,3)

                    select * from fktest1
                    select * from fktest2

                    update fktest1 set id=11 where id=1
                    update fktest1 set id=22 where id=2
                    update fktest1 set id=33 where id=3
                    delete from fktest1 where id > 22

                    select * from fktest1
                    select * from fktest2





                    share|improve this answer













                    Trigger is solution for this problem:



                    IF OBJECT_ID('dbo.fktest2', 'U') IS NOT NULL
                    drop table fktest2
                    IF OBJECT_ID('dbo.fktest1', 'U') IS NOT NULL
                    drop table fktest1
                    IF EXISTS (SELECT name FROM sysobjects WHERE name = 'fkTest1Trigger' AND type = 'TR')
                    DROP TRIGGER dbo.fkTest1Trigger
                    go
                    create table fktest1 (id int primary key, anQId int identity)
                    go
                    create table fktest2 (id1 int, id2 int, anQId int identity,
                    FOREIGN KEY (id1) REFERENCES fktest1 (id)
                    ON DELETE CASCADE
                    ON UPDATE CASCADE/*,
                    FOREIGN KEY (id2) REFERENCES fktest1 (id) this causes compile error so we have to use triggers
                    ON DELETE CASCADE
                    ON UPDATE CASCADE*/
                    )
                    go

                    CREATE TRIGGER fkTest1Trigger
                    ON fkTest1
                    AFTER INSERT, UPDATE, DELETE
                    AS
                    if @@ROWCOUNT = 0
                    return
                    set nocount on

                    -- This code is replacement for foreign key cascade (auto update of field in destination table when its referenced primary key in source table changes.
                    -- Compiler complains only when you use multiple cascased. It throws this compile error:
                    -- Rrigger Introducing FOREIGN KEY constraint on table may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION,
                    -- or modify other FOREIGN KEY constraints.
                    IF ((UPDATE (id) and exists(select 1 from fktest1 A join deleted B on B.anqid = A.anqid where B.id <> A.id)))
                    begin
                    update fktest2 set id2 = i.id
                    from deleted d
                    join fktest2 on d.id = fktest2.id2
                    join inserted i on i.anqid = d.anqid
                    end
                    if exists (select 1 from deleted)
                    DELETE one FROM fktest2 one LEFT JOIN fktest1 two ON two.id = one.id2 where two.id is null -- drop all from dest table which are not in source table
                    GO

                    insert into fktest1 (id) values (1)
                    insert into fktest1 (id) values (2)
                    insert into fktest1 (id) values (3)

                    insert into fktest2 (id1, id2) values (1,1)
                    insert into fktest2 (id1, id2) values (2,2)
                    insert into fktest2 (id1, id2) values (1,3)

                    select * from fktest1
                    select * from fktest2

                    update fktest1 set id=11 where id=1
                    update fktest1 set id=22 where id=2
                    update fktest1 set id=33 where id=3
                    delete from fktest1 where id > 22

                    select * from fktest1
                    select * from fktest2






                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Dec 3 '15 at 14:18









                    Tone ŠkodaTone Škoda

                    8791217




                    8791217























                        0














                        This is an error of type database trigger policies. A trigger is code and can add some intelligences or conditions to a Cascade relation like Cascade Deletion. You may need to specialize the related tables options around this like Turning off CascadeOnDelete:



                        protected override void OnModelCreating( DbModelBuilder modelBuilder )
                        {
                        modelBuilder.Entity<TableName>().HasMany(i => i.Member).WithRequired().WillCascadeOnDelete(false);
                        }


                        Or Turn off this feature completely:



                        modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();





                        share|improve this answer




























                          0














                          This is an error of type database trigger policies. A trigger is code and can add some intelligences or conditions to a Cascade relation like Cascade Deletion. You may need to specialize the related tables options around this like Turning off CascadeOnDelete:



                          protected override void OnModelCreating( DbModelBuilder modelBuilder )
                          {
                          modelBuilder.Entity<TableName>().HasMany(i => i.Member).WithRequired().WillCascadeOnDelete(false);
                          }


                          Or Turn off this feature completely:



                          modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();





                          share|improve this answer


























                            0












                            0








                            0







                            This is an error of type database trigger policies. A trigger is code and can add some intelligences or conditions to a Cascade relation like Cascade Deletion. You may need to specialize the related tables options around this like Turning off CascadeOnDelete:



                            protected override void OnModelCreating( DbModelBuilder modelBuilder )
                            {
                            modelBuilder.Entity<TableName>().HasMany(i => i.Member).WithRequired().WillCascadeOnDelete(false);
                            }


                            Or Turn off this feature completely:



                            modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();





                            share|improve this answer













                            This is an error of type database trigger policies. A trigger is code and can add some intelligences or conditions to a Cascade relation like Cascade Deletion. You may need to specialize the related tables options around this like Turning off CascadeOnDelete:



                            protected override void OnModelCreating( DbModelBuilder modelBuilder )
                            {
                            modelBuilder.Entity<TableName>().HasMany(i => i.Member).WithRequired().WillCascadeOnDelete(false);
                            }


                            Or Turn off this feature completely:



                            modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();






                            share|improve this answer












                            share|improve this answer



                            share|improve this answer










                            answered Oct 10 '14 at 11:35









                            Amirhossein MehrvarziAmirhossein Mehrvarzi

                            7,37542952




                            7,37542952























                                -2














                                My solution to this problem encountered using ASP.NET Core 2.0 and EF Core 2.0 was to perform the following in order:




                                1. Run update-database command in Package Management Console (PMC) to create the database (this results in the "Introducing FOREIGN KEY constraint ... may cause cycles or multiple cascade paths." error)


                                2. Run script-migration -Idempotent command in PMC to create a script that can be run regardless of the existing tables/constraints


                                3. Take the resulting script and find ON DELETE CASCADE and replace with ON DELETE NO ACTION


                                4. Execute the modified SQL against the database



                                Now, your migrations should be up-to-date and the cascading deletes should not occur.



                                Too bad I was not able to find any way to do this in Entity Framework Core 2.0.



                                Good luck!






                                share|improve this answer
























                                • You can change your migration file to do so (without changing sql script), i.e. in your migration file you can set onDelete action to Restrict from Cascade

                                  – Rushi Soni
                                  Mar 17 '18 at 11:46











                                • It's better to specify this using fluent annotations so that you don't have to remember to do this if you end up deleting and recreating your migrations folder.

                                  – Allen Wang
                                  May 1 '18 at 15:08











                                • In my experience, the fluent annotations can be used and should be used (I use them) but they are often be quite buggy. Simply specifying them in the code doesn't always work produce the expected result.

                                  – user1477388
                                  May 2 '18 at 10:21
















                                -2














                                My solution to this problem encountered using ASP.NET Core 2.0 and EF Core 2.0 was to perform the following in order:




                                1. Run update-database command in Package Management Console (PMC) to create the database (this results in the "Introducing FOREIGN KEY constraint ... may cause cycles or multiple cascade paths." error)


                                2. Run script-migration -Idempotent command in PMC to create a script that can be run regardless of the existing tables/constraints


                                3. Take the resulting script and find ON DELETE CASCADE and replace with ON DELETE NO ACTION


                                4. Execute the modified SQL against the database



                                Now, your migrations should be up-to-date and the cascading deletes should not occur.



                                Too bad I was not able to find any way to do this in Entity Framework Core 2.0.



                                Good luck!






                                share|improve this answer
























                                • You can change your migration file to do so (without changing sql script), i.e. in your migration file you can set onDelete action to Restrict from Cascade

                                  – Rushi Soni
                                  Mar 17 '18 at 11:46











                                • It's better to specify this using fluent annotations so that you don't have to remember to do this if you end up deleting and recreating your migrations folder.

                                  – Allen Wang
                                  May 1 '18 at 15:08











                                • In my experience, the fluent annotations can be used and should be used (I use them) but they are often be quite buggy. Simply specifying them in the code doesn't always work produce the expected result.

                                  – user1477388
                                  May 2 '18 at 10:21














                                -2












                                -2








                                -2







                                My solution to this problem encountered using ASP.NET Core 2.0 and EF Core 2.0 was to perform the following in order:




                                1. Run update-database command in Package Management Console (PMC) to create the database (this results in the "Introducing FOREIGN KEY constraint ... may cause cycles or multiple cascade paths." error)


                                2. Run script-migration -Idempotent command in PMC to create a script that can be run regardless of the existing tables/constraints


                                3. Take the resulting script and find ON DELETE CASCADE and replace with ON DELETE NO ACTION


                                4. Execute the modified SQL against the database



                                Now, your migrations should be up-to-date and the cascading deletes should not occur.



                                Too bad I was not able to find any way to do this in Entity Framework Core 2.0.



                                Good luck!






                                share|improve this answer













                                My solution to this problem encountered using ASP.NET Core 2.0 and EF Core 2.0 was to perform the following in order:




                                1. Run update-database command in Package Management Console (PMC) to create the database (this results in the "Introducing FOREIGN KEY constraint ... may cause cycles or multiple cascade paths." error)


                                2. Run script-migration -Idempotent command in PMC to create a script that can be run regardless of the existing tables/constraints


                                3. Take the resulting script and find ON DELETE CASCADE and replace with ON DELETE NO ACTION


                                4. Execute the modified SQL against the database



                                Now, your migrations should be up-to-date and the cascading deletes should not occur.



                                Too bad I was not able to find any way to do this in Entity Framework Core 2.0.



                                Good luck!







                                share|improve this answer












                                share|improve this answer



                                share|improve this answer










                                answered Nov 28 '17 at 20:37









                                user1477388user1477388

                                13.2k2199201




                                13.2k2199201













                                • You can change your migration file to do so (without changing sql script), i.e. in your migration file you can set onDelete action to Restrict from Cascade

                                  – Rushi Soni
                                  Mar 17 '18 at 11:46











                                • It's better to specify this using fluent annotations so that you don't have to remember to do this if you end up deleting and recreating your migrations folder.

                                  – Allen Wang
                                  May 1 '18 at 15:08











                                • In my experience, the fluent annotations can be used and should be used (I use them) but they are often be quite buggy. Simply specifying them in the code doesn't always work produce the expected result.

                                  – user1477388
                                  May 2 '18 at 10:21



















                                • You can change your migration file to do so (without changing sql script), i.e. in your migration file you can set onDelete action to Restrict from Cascade

                                  – Rushi Soni
                                  Mar 17 '18 at 11:46











                                • It's better to specify this using fluent annotations so that you don't have to remember to do this if you end up deleting and recreating your migrations folder.

                                  – Allen Wang
                                  May 1 '18 at 15:08











                                • In my experience, the fluent annotations can be used and should be used (I use them) but they are often be quite buggy. Simply specifying them in the code doesn't always work produce the expected result.

                                  – user1477388
                                  May 2 '18 at 10:21

















                                You can change your migration file to do so (without changing sql script), i.e. in your migration file you can set onDelete action to Restrict from Cascade

                                – Rushi Soni
                                Mar 17 '18 at 11:46





                                You can change your migration file to do so (without changing sql script), i.e. in your migration file you can set onDelete action to Restrict from Cascade

                                – Rushi Soni
                                Mar 17 '18 at 11:46













                                It's better to specify this using fluent annotations so that you don't have to remember to do this if you end up deleting and recreating your migrations folder.

                                – Allen Wang
                                May 1 '18 at 15:08





                                It's better to specify this using fluent annotations so that you don't have to remember to do this if you end up deleting and recreating your migrations folder.

                                – Allen Wang
                                May 1 '18 at 15:08













                                In my experience, the fluent annotations can be used and should be used (I use them) but they are often be quite buggy. Simply specifying them in the code doesn't always work produce the expected result.

                                – user1477388
                                May 2 '18 at 10:21





                                In my experience, the fluent annotations can be used and should be used (I use them) but they are often be quite buggy. Simply specifying them in the code doesn't always work produce the expected result.

                                – user1477388
                                May 2 '18 at 10:21





                                protected by Community May 29 '15 at 7:39



                                Thank you for your interest in this question.
                                Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).



                                Would you like to answer one of these unanswered questions instead?



                                Popular posts from this blog

                                Wiesbaden

                                Marschland

                                Dieringhausen