2013-07-04 7 views
8

Ho una tabella utente e una tabella ruoli. Esiste una tabella di collegamenti UsersRoles generata automaticamente che contiene l'Id delle tabelle Utente e Ruoli. Questo viene generato utilizzando il seguente codice:Violazione del vincolo PRIMARY KEY nella tabella di collegamento del primo codice Entity Framework

modelBuilder.Entity<User>() 
       .HasMany(u => u.Roles) 
       .WithMany(r => r.Users) 
       .Map(c => { 
        c.MapLeftKey("UserId"); 
        c.MapRightKey("RoleId"); 
        c.ToTable("UsersRoles"); 
       }); 

Quando cerco di aggiungere un'entità estranea e chiamare Context.SaveChanges() ricevo il seguente errore:

Violation of PRIMARY KEY constraint 'PK_UsersRoles'. Cannot insert duplicate key in object 'dbo.UsersRoles'. The duplicate key value is (2beaf837-9034-4376-9510-b1609c54efbe, dcd16d00-d46e-4d48-8328-3e7b35b11ccf). The statement has been terminated.

Ho controllato il Conext.ChangeTracker.Entries() per gli elementi di cui al l'errore e lo stato dell'entità sono contrassegnati come invariato.

L'unica entità contrassegnata come aggiunta è il nuovo record che sto tentando di aggiungere, tutto il resto è contrassegnato come Invariato.

codice per l'aggiunta di Entity:

RoleGroup group = Context.RoleGroups.Create(); 
group.Title = roleGroupName; 
Context.Set<RoleGroup>().Add(group); 
Context.SaveChanges(); 

Qualcuno sa perché questo sta accadendo?

+0

Dovresti pubblicare il codice che aggiunge l'entità al contesto – ken2k

+0

Puoi mostrare * esattamente * quello che hai controllato? Ho il sospetto che tu abbia verificato solo che le entità 'Role' e' User' non siano cambiate. – hvd

+0

Grazie per le domande, ho aggiornato la mia domanda per aggiungere ulteriori informazioni. Speriamo che questo aiuti. – 97ldave

risposta

5

Il fatto che il User con UserId = 2beaf837-9034-4376-9510-b1609c54efbe e la Role con RoleId = dcd16d00-d46e-4d48-8328-3e7b35b11ccf sono in stato Unchanged non significa che nulla viene scritto nel database.

Soprattutto per molti-a-molti (in generale per le associazioni indipendenti) EF mantiene uno stato per il rapporto stessa, che è diverso dal entità Stato. Se una voce viene inserita nella tabella dei collegamenti, significa che la voce della relazione per le due entità in questione è nello stato Added sebbene lo stato dell'entità per tali entità sia Unchanged. Non è possibile visualizzare la voce della relazione quando si enumera lo DbContext s ChangeTracker. Restituirà solo stati di entità. Devi passare al sottostante ObjectContext per richiedere lo stato della relazione.

Esempio:

using (var ctx = new MyContext()) 
{ 
    var user = ctx.Users.Find(1); 
    var role = ctx.Roles.Find(5); 

    user.Roles = new List<Role>(); 
    user.Roles.Add(role); 

    ctx.SaveChanges(); 
} 

Qui user e role saranno sia in stato Unchanged, ma ancora un record viene inserito nella tabella di collegamento. E questo codice genererà la tua eccezione se l'utente 1 e il ruolo 5 sono già collegati nel database.

L'aggiunta di group non ha nulla a che fare con il problema. Solo la chiamata a SaveChanges causa l'eccezione perché molto probabilmente hai creato una relazione tra le due entità da qualche parte prima dello snippet di codice nella tua domanda.

1

Si sta tentando di inserire la stessa combinazione di utente/ruolo nella tabella UserRoles:

Violation of PRIMARY KEY constraint 'PK_UsersRoles'. Cannot insert duplicate key in object 'dbo.UsersRoles'. The duplicate key value is (2beaf837-9034-4376-9510-b1609c54efbe, dcd16d00-d46e-4d48-8328-3e7b35b11ccf). The statement has been terminated.

Controllare per vedere quale utente ha la ID di 2beaf837-9034-4376-9510-b1609c54efbe, e quale ruolo ha l'ID di dcd16d00-d46e-4d48-8328-3e7b35b11ccf. Se sei sicuro di averlo inserito solo una volta, il metodo che inserisce i dati viene chiamato più volte senza che tu te ne accorga?

6

Per aggiungere alla risposta di Slauma, sembra che se si imposta la proprietà ICollection su uno di questi elementi automatici molti-a-molti, EF si confonde e non si rende conto che si stanno cancellando gli elementi delle raccolte facendo ciò.

Così, invece di fare questo:

user.Roles = new List<Role>(); 
user.Roles.Add(role); 

quello che dovete fare questo:

user.Roles.Clear(); 
user.Roles.Add(role); 

questo ha funzionato per me.

Non dovresti farlo comunque. Questo dovrebbe essere un bug in EF.

+0

Ho appena avuto lo stesso problema qui. Sicuramente dovrebbe essere considerato un bug. – Don

+0

Lo stesso problema qui. Nel mio caso, ho una proprietà di navigazione su un oggetto figlio in una configurazione table-per-heirarchy. Per farlo funzionare correttamente, devo caricare manualmente i figli dell'entità tramite DbContext.Entry (entity) .Collection (x => x.Children) .Load(). Basta caricarli attraverso una query non è sufficiente. Quindi per aggiornare la lista, devo cancellare e aggiungere le nuove voci. – Triynko

0

Sperando che qualcuno lo trovi utile ho scoperto che c'è una grande differenza tra la modifica di una lista esistente in EF rispetto alla creazione di una nuova lista.

In questo caso stavo facendo un aggiornamento e ho pensato che fosse più semplice semplicemente creare una nuova lista degli articoli che volevo. Ma se alcuni degli articoli fossero già stati aggiunti alla lista, otterrei una violazione della chiave primaria durante il salvataggio.

Ho finito per mantenere la stessa lista e solo apportando modifiche ad esso. Cancellarlo e leggere era ok, creare una nuova lista non lo era.