2014-12-23 6 views
14

Użytkownik, pracodawca, kandydat i praca, pracodawca może utworzyć wiele zleceń, a każde zlecenie może mieć tylko jednego pracodawcę, kandydat może ubiegać się o wiele zleceń, a każde zlecenie może składać się z wielu członków.Wprowadzenie ograniczenia FOREIGN KEY może powodować cykle lub wiele ścieżek kaskadowych. Podaj przy usuwaniu brak działania

więc związek jest tak:

enter image description here

Używam jednostka kodu ramy pierwsze podejście, w tej chwili, jeśli usunę pracodawca ma zamiar usunąć wszystkie powiązane zadania, a użytkownik z bazy danych, a jeśli usunę kandydata, że ​​ma zamiar usunąć użytkownika:

modelBuilder.Entity<Employer>() 
    .HasRequired(e => e.User) 
    .WithOptional(e => e.Employer).WillCascadeOnDelete(); 

//member is candidate 
modelBuilder.Entity<Member>() 
    .HasRequired(e => e.User) 
    .WithOptional(e => e.Member).WillCascadeOnDelete(); 

modelBuilder.Entity<Employer>() 
    .HasMany(a => a.Jobs) 
    .WithRequired(b => b.Employer) 
    .WillCascadeOnDelete(); 

Wszystko działa poprawnie z wyjątkiem kiedy podać wiele do wielu relacji między kandydatami i pracy i aktualizuje bazę danych przy użyciu „update-baza ”, To daje mi ten błąd:

Wprowadzenie ograniczenia klucz obcy«FK_dbo.MemberJobMap_dbo.Jobs_JobId»na stole«MemberJobMap»może powodować cykli lub wiele ścieżek kaskadowe. Określ ON DELETE NO ACTION lub ON UPDATE NO ACTION lub zmodyfikuj inne ograniczenia klucza OBCEGO. Nie można utworzyć ograniczenia. Zobacz poprzednie błędy.

Oto jak podano wiele do wielu relacji:

modelBuilder.Entity<Member>() 
    .HasMany(m => m.Jobs) 
    .WithMany(j => j.Members) 
    .Map(c => 
    { 
     c.MapLeftKey("Id"); 
     c.MapRightKey("JobId"); 
     c.ToTable("MemberJobMap"); 
    }); 

i kiedy dodać migracji:

CreateTable(
    "dbo.MemberJobMap", 
    c => new 
    { 
     Id = c.String(nullable: false, maxLength: 128), 
     JobId = c.Int(nullable: false), 
    }) 
    .PrimaryKey(t => new { t.Id, t.JobId }) 
    .ForeignKey("dbo.Members", t => t.Id, cascadeDelete: true) 
    .ForeignKey("dbo.Jobs", t => t.JobId, cascadeDelete: true) 
    .Index(t => t.Id) 
    .Index(t => t.JobId); 

Próbuję zmienić cascadeDelete się fałszywe, ale to daje mi błąd, gdy usunę kandydat, który złożył podanie lub gdy próbuję usunąć pracę z kandydującymi kandydatami.

Jak naprawić ten błąd? Tak że:

  1. Kiedy zadanie zostanie usunięte, to będzie usunąć skojarzone tabeli candidatejobmap wierszy bez dokonania jakiejkolwiek innej tabeli
  2. Gdy kandydat zostanie usunięty, to będzie usunąć skojarzone tabeli candidatejobmap wiersze i stół użytkownik wiersz bez dokonywania jakichkolwiek innej tabeli
  3. Przy zachowaniu wszystkich innych określonych kaskada usuwać działania samo

Odpowiedz

11

Mam ustalony ten problem

Problem pojawia się, ponieważ mam dwa kaskadowy usunąć ścieżkę do stołu CandidateJobMap:

Jeśli usunę pracodawcy, jego zamiar usunąć zadania pracodawcy związane który w skręcić usuwać CandidateJobMap tabeli:

Employer-> Warszawie na> CandidateJobMap

Jeśli usunę kandydata, jego zamiar dele Te CandidateJobMap tabela:

Member-> CandidateJobMap

Tak, aby obejść ten problem, muszę wyłączyć jeden z usuwania ścieżki, nie można określić WillCascadeDelete (false) podczas tworzenia wielu do wielu relacji, tak zamiast trzeba zmienić migrację następująco:

CreateTable(
    "dbo.MemberJobMap", 
    c => new 
    { 
     Id = c.String(nullable: false, maxLength: 128), 
     JobId = c.Int(nullable: false), 
    }) 
    .PrimaryKey(t => new { t.Id, t.JobId }) 
    .ForeignKey("dbo.Members", t => t.Id, cascadeDelete: false) <--------cascade delete to false 
    .ForeignKey("dbo.Jobs", t => t.JobId, cascadeDelete: true) 
    .Index(t => t.Id) 
    .Index(t => t.JobId); 

teraz, ponieważ można ustawić kaskada usuwać false, gdy kandydat został usunięty, to nie usunie powiązane wiersze CandidateJobMap, spowoduje to kolejny błąd podczas próby usuń kandydata, który jest również kluczem pokrewnym w CandidateJobMap, więc musisz ręcznie usunąć r Pijany wiersze CandidateJobMap przed wyjęciem kandydata:

//remove all applied jobs from user, without doing this, you will receive an error 
foreach (var appliedjob in user.Member.Jobs.ToList()) 
{ 
    user.Member.Jobs.Remove(appliedjob); 
} 

//before you can delete the user 
await UserManager.DeleteAsync(user); 

Nie wiem, czy jest to najlepszy sposób, ale pracował dla mnie.

+0

ukryłeś problem, usuwanie kaskadowe powinno działać z dowolnej strony tabeli łączenia. to nie pachnie jak błąd w ER M, albo błędem w sposobie, w jaki go używasz. – Jasen

+0

@Jasen Proszę wyjaśnić, ponieważ kaskadowe usuwanie z obu stron nie działa dla mnie, daje mi błąd, o który poprosiłem – Mindless

+1

Tak, mam jeszcze prostszą konfigurację z pojedynczą jednostką "wiele do wielu" i otrzymuję ten sam błąd, gdy Próbuję włączyć usuwanie kaskadowe zarówno z jednego do wielu relacji w tym samym czasie.Myślę, że jest to po prostu ograniczenie SQL Server. –

2

Chciałbym zaprojektować I coś takiego ...

User_Type <-- Tow types of users Candidates and Employers  


USERS  <-- Common Fields for Candidates and Employers , along with one column to 
      -- identify if it is Candidate or an Employer referencing back to User_Type 

Emp_Details <-- Only columns that an employer will have referencing back to Users table 

Can_Details <-- Only columns that a Candidate will have referencing back to Users table 

Jobs   <-- Jobs published by a user who is an employer referencing back to Users table 

CandidateJobs <-- A composite key referencing back to Jobs(JobId) and Users who are 
       --Candidates 
+0

Dzięki za odpowiedź, mój obecny związek jest bardzo podobna do tej, którą zaproponował Empolyer i Candadidates są podstawowe Emp_Details i Can_Details stół, mam tabeli role zdefiniowane, ale Nie wspomniałem o tym, ponieważ uważam, że nie ma to znaczenia dla pytania, chciałbym, aby kandydaci i pracodawcy odnosili się do tej samej tabeli stanowisk o różnych relacjach (jeden do wielu i wielu do wielu). – Mindless

3

Zdaję sobie sprawę, że jest to dość stary problem, ale wpadłem na ten sam problem i istnieją komentarze, które nie zostały uwzględnione.

Konkretnie „masz ukryty problem ...”

Cascade z wielu ścieżek powinien praca, ponieważ jest to ważne, że usunięcie albo przodka powinno skutkować usunięciem potomka. Ale to tylko teoretycznie, w rzeczywistości SQL Server po prostu na to nie pozwala, stąd błąd. Jedno rozwiązanie jest w tym poście tutaj solving-the-sql-server-multiple-cascade-path-issue-with-a-trigger.

Sugeruje usunięcie wszystkich działań powodujących kaskadę i zastąpienie ich wszystkimi wyzwalaczami, aby usunąć rekordy. Wolę pracować na najwyższym poziomie łańcucha kaskadowego. W jego przykładzie po prostu odciąłem go na "rodzicielskim" zapisie z INSTEAD OF DELETE dla dzieci i niech kaskada zajmie się resztą.

Robię to z dwóch powodów

  1. Należy to zrobić w bazie danych, ponieważ jest to ostatnia linia obrony dla złych danych ... trochę jak opróżniania kieszeni tuż przed ubrania iść w pralka. Zajmowanie się tym oznacza, że ​​nie musisz replikować kodu do wszystkich różnych modeli, z których możesz zbudować ten jeden DB w przyszłości, ani nie musisz liczyć na wszystkich nowych programistów, którzy się tym zajmą.

  2. robienie tego w najwyższym przodku pozwoli pozostać wszystkim innym związkom, w tym takim, które można dodać w przyszłości.

Nadzieja to pomaga, Mike