2011-09-24 14 views
14

Questo mi ha fatto impazzire per gli ultimi 2 giorni. Ho 3 classi abbastanza di base (beh, ridotto per migliorare la leggibilità)EF 4.1 e "La raccolta è stata modificata, l'operazione di enumerazione potrebbe non essere eseguita." eccezione

public class Employee 
{ 
    public string Name { set; get; } 
    virtual public Employer Employer { set; get; } 

    public Employee(string name) 
    { 
     this.Name = name; 
    } 
} 

,

// this basically ties Employee and his role in a company. 
public class EmployeeRole{ 
    public int Id { set; get; } 
    virtual public Employee Employee { set; get; } 
    public string Role { set; get; } 

    public EmployeeRole(Employee employee, string role){ 
     this.Employee = employee; 
     this.Role = role; 
    } 
} 

e

public class Employer{ 

    public string Name { set; get; } 
    List<EmployeeRole> employees = new List<EmployeeRole>(); 
    virtual public List<EmployeeRole> Employees { get { return this.employees; } } 

    public Employer(string name, Employee creator){ 
     this.Name = name; 
     this.Employees.Add(new EmployeeRole(creator, "Creator")); 
     creator.Employer = this; 
    } 
} 

sembra abbastanza semplice. Non si esegue alcuna configurazione specifica per tali classi in DbContext.

Ma, quando ho eseguito seguente codice

using (DbContext db = DbContext.GetNewDbContext()){ 

    Employee creator = new Employee("Bob"); 
    db.Employees.Add(creator); 
    db.SaveChanges(); 

    Employer employer = new Employer("employer", creator); 
    db.Employers.Add(employer); 
    db.SaveChanges(); 
    // I know I can call SaveChanges once (and it actually works in this case), 
    // but I want to make sure this would work with saved entities. 
} 

getta seguente eccezione:

Collection è stato modificato; l'operazione di enumerazione potrebbe non essere eseguita.

traccia stack:

a System.ThrowHelper.ThrowInvalidOperationException (ExceptionResource risorse) a System.Collections.Generic.List 1.Enumerator.MoveNextRare() at System.Collections.Generic.List 1.Enumerator.MoveNext() in System.Data.Objects .ObjectStateManager.PerformAdd (IList iscrizioni) a System.Data.Objects.ObjectStateManager.DetectChanges() a System.Data.Objects.ObjectContext.DetectChanges() a System.Data.Entity.Internal.InternalContext.Dete ctChanges (booleano vigore) System.Data.Entity.Internal.Linq.InternalSet 1.ActOnSet(Action action, EntityState newState, Object entity, String methodName) at System.Data.Entity.Internal.Linq.InternalSet 1.Add (entità Object)
a System.Data.Entity.DbSet`1.Add (entità TEntity)

Qualcuno ha un'idea di cosa sta succedendo e forse come risolverlo? Grazie!

+1

Si ha la proprietà 'Datore di lavoro' su 'Dipendente' e' Elenco 'sulla classe' Datore di lavoro'! Non possono mappare insieme senza ulteriori informazioni. Per favore lascia qui il codice completo o più spieghi il tuo scopo. Oppure puoi caricare uno screenshot dello schema del database qui per favore? –

+0

http://social.msdn.microsoft.com/Forums/en-US/1a49f75d-5168-4829-95f8-02eae38a3ee3/entityframework-41-exception-collection-was-modified-enumeration-operation-may-not-execute – Mohsen

risposta

2

Ho avuto lo stesso problema. Sembra un bug in EF.

Ho modificato il mio codice per aggiungere esplicitamente l'entità al contesto EF prima di impostarlo su qualsiasi altra proprietà di entità.

+2

Puoi spiegare cosa hai fatto esattamente? –

16

Per me questo sembra un bug in Entity Framework. Ho cucinato il vostro esempio ad uno più semplice, ma con la stessa struttura:

public class TestA // corresponds to your Employee 
{ 
    public int Id { get; set; } 
    public TestB TestB { get; set; } // your Employer 
} 

public class TestB // your Employer 
{ 
    public TestB() 
    { 
     TestCs = new List<TestC>(); 
    } 

    public int Id { get; set; } 
    public ICollection<TestC> TestCs { get; set; } // your EmployeeRoles 
} 

public class TestC // your EmployeeRole 
{ 
    public int Id { get; set; } 
    public TestA TestA { get; set; } // your Employee 
} 

sono queste tre entità con le relazioni cicliche:

TestA -> TestB -> TestC -> TestA 

Se io uso ora un codice corrispondente con la stessa struttura della tua ottengo la stessa eccezione:

var testA = new TestA(); 
var testB = new TestB(); 
var testC = new TestC(); 

context.TestAs.Add(testA); 

testA.TestB = testB; 
testB.TestCs.Add(testC); 
testC.TestA = testA; 

context.ChangeTracker.DetectChanges(); 

Nota che ho usato al posto del DetectChangesSaveChanges perché l'analisi dello stack nell'eccezione chiarisce che in realtà DetectChanges causa l'eccezione (che è chiamata internamente da SaveChanges). Ho anche scoperto che chiamare il numero SaveChanges due volte non è un problema. Il problema qui è solo l'aggiunta "anticipata" al contesto prima che l'intero grafico dell'oggetto sia completato.

La raccolta che è stata modificata (come si lamenta l'eccezione) è non la raccolta TestB.TestCs nel modello. Sembra essere una raccolta di voci nello ObjectStateManager. Potrei verificare questo sostituendo ICollection<TestC> TestCs con un riferimento singolo da TestC TestC nella classe TestB. In questo modo il modello non contiene alcuna collezione, ma getta comunque la stessa eccezione su una collezione modificata. (SaveChanges non riuscirà comunque con tre riferimenti singoli perché EF non sa in che ordine salvare le entità a causa del ciclo, ma questo è un altro problema.)

Lo considererei un bug per il rilevamento del cambio EF (DetectChanges) sembra modificare la propria raccolta interna, sta solo iterando.

Ora, la correzione a questo problema è semplice: basta Add entità al contesto come il vostro ultimo passo prima di chiamare SaveChanges:

var testA = new TestA(); 
var testB = new TestB(); 
var testC = new TestC(); 

testA.TestB = testB; 
testB.TestCs.Add(testC); 
testC.TestA = testA; 

context.TestAs.Add(testA); 

context.ChangeTracker.DetectChanges(); 

EF aggiungerà il relativo intero grafo oggetto al contesto. Questo codice ha esito positivo (anche utilizzando SaveChanges anziché DetectChanges).

O il vostro esempio:

using (DbContext db = DbContext.GetNewDbContext()){ 
    Employee creator = new Employee("Bob"); 
    Employer employer = new Employer("employer", creator); 

    db.Employees.Add(creator); 
    db.SaveChanges(); 
} 

Modifica

Questa era la stessa eccezione: Entity Framework throws "Collection was modified" when using observable collection. Seguendo il codice in questo esempio, la situazione era simile: aggiunta di un'entità al contesto e successivamente modifica/aggiunta di relazioni a quell'entità.

Edit2

È interessante notare che questo getta la stessa eccezione:

var testA = context.TestAs.Find(1); // assuming there is already one in the DB 
var testB = new TestB(); 
var testC = new TestC(); 

testA.TestB = testB; 
testB.TestCs.Add(testC); 
testC.TestA = testA; 

context.SaveChanges(); // or DetectChanges, it doesn't matter 

Quindi, voglio aggiungere relazioni con nuovi soggetti per l'entità esistente. Una soluzione a questo problema sembra essere meno ovvia.

+0

Qualsiasi seguito su questo. Sembra che abbia lo stesso problema. C'è qualche problema? Ho davvero bisogno di aggiungere dati esistenti a nuove istanze. È aggiunto come bug? – Michael

+0

@ Michael: No, niente di nuovo su questo dal mio lato. – Slauma

+0

Ho anche questo problema, ho bisogno di una correzione – JarrettV

2

Mi sono appena imbattuto in questo problema. Quello che ho trovato è che EF odia riferimenti circolari indiretti. Nel tuo caso lo sembra Il datore di lavoro dovrebbe possedere il rapporto con il dipendente. Quindi togli il riferimento al datore di lavoro dalla classe dei dipendenti.

0

Mi sono imbattuto nello stesso problema questa mattina, nel mio caso ho avuto un'associazione "Dipendente-Manager" definita con una relazione circolare. Ad esempio:

public class Employee 
{ 
    public string Name { set; get; } 
    virtual public Employee Manager { set; get; } 

    public Employee() 
    { 

    } 
} 

L'app si arrestava in modo anomalo con l'errore sopra riportato durante l'impostazione della proprietà Manager. Alla fine risultò essere una brutta implementazione del metodo GetHashCode() nella classe Employee.Sembrava che EF non fosse in grado di individuare l'entità modificata poiché il confronto tra le entità stava fallendo; quindi, EF pensava che la collezione fosse stata modificata.

Problemi correlati