2016-06-23 25 views
6

sto ottenendo l'erroreEntity Framework "Un oggetto entità non può fare riferimento più istanze di IEntityChangeTracker"

Un oggetto entità non può fare riferimento più istanze di IEntityChangeTracker

quando si cerca di crea una nuova entità e salvala nel DB.

Capisco l'errore e come si verifica normalmente, ma in questo caso tutto ciò che sto facendo è creare una nuova entità e aggiungerne alcuni int s prima di salvare, non aggiungere altre entità da altri contesti.

Ho incluso la funzione che causa l'errore. Come puoi vedere, viene passato un EndProduct che è un'entità che viene tracciata da un contesto diverso da quello nello _billableRepository, ma poiché non sto provando ad assegnare comunque quell'entità al conto appena creato, non lo faccio guarda come può essere un problema.

L'unico modo che posso vedere l'errore accade è perché un paio di int valori che vengono assegnati alla nuova Billable sono presi da quello esistente EndProduct che viene monitorata da un contesto diverso, ma sicuramente la IEntityChangeTracker doesn' t tracciare i singoli primitivi di un'entità?

public void AddBillable(EndProduct endProduct, int? purchaseId, string centreCode, int userId) 
{ 
    if (endProduct.Product != null) 
    { 
     var existingBillableForUserForProductId = _billableRepository.GetQuery(b => b.UserId == userId && b.ProductId == endProduct.ProductId); 
     if (endProduct.BillablePartId != null && !existingBillableForUserForProductId.Any()) 
     { 
      var billable = new Billable { 
       ProductId = endProduct.ProductId.Value, //int 
       UserId = userId, //int 
       PartId = endProduct.BillablePartId.Value, //int 
       DateAdded = DateTime.UtcNow, //datetime 
       PurchaseId = purchaseId, //int 
       CentreCode = centreCode //string 
      }; 

      _billableRepository.Add(billable); //error here 
      _billableRepository.UnitOfWork.SaveChanges(); 
     } 
    } 
} 
+0

Prova questo. _billableRepository.Billable.Add (fatturabile); _billableRepository.SaveChanges(); – NEER

+0

Stai smaltendo il tuo contesto correttamente ogni volta? Dovresti inizializzarlo appena prima di averne bisogno e smaltirlo il prima possibile. –

risposta

10

La causa più probabile di questo è lo strumento di iniezione delle dipendenze che si sta utilizzando.

Ci deve essere solo uno DbContext in gioco per unità di lavoro. Se ne stai iniziando uno nuovo ogni volta, assicurati che quello vecchio sia stato eliminato.

In caso contrario, si avranno più istanze dello stesso contesto che corrono l'una di fianco all'altra.

Qui è dove il tracker delle modifiche viene confuso e non è in grado di tenere traccia delle modifiche alle entità.

+0

Probabilmente hai ragione.Al momento stiamo iniettando un contesto per repository, quindi sicuramente _o_ abbiamo più contesti simultanei. È qualcosa che stiamo cercando di aggiornare su tutto il codice base. Nel frattempo non esiste un modo semplice per passare a un singolo contesto per richiesta o simile. Comunque non pensavo che avrebbe avuto importanza qui perché, per quanto posso dire, qui è davvero in gioco un solo contesto, quello per '_billableRepository' – Anduril

1

È possibile risolvere il problema allegando l'entità nel repository. In questo modo:

_context.Set<T>.Attach(entity) 

Dove impostare il proprio DbSet nel contesto.

+0

Questo non aiuta se l'entità è già associata a un'altra istanza di context ... – Bartosz

1

Questo codice di esempio risolverà il problema;

public class DataModel 
    { 
     private static DBContext context; 
     public static DBContext Context 
     { 
      get 
      { 
       if (context == null) 
       { 
        context = new SozlukContext(); 
        return context; 
       } 
       return context; 
      } 
     } 
    } 
public class EntryRepository : IEntryRepository 
    { 
     DBContext _context = DataModel.Context; 
     public IEnumerable<Data.Model.Entry> GetAll() 
     { 
      return _context.Entry.Select(x => x); 
     } 
    } 
+0

Le risposte al solo codice non sono incoraggiate in quanto non forniscono molte informazioni per i futuri lettori, per favore fornite alcune spiegazioni su ciò che avete scritto – WhatsThePoint

+0

Penso che sia tutto chiaro. Ho una connessione e un'operazione di richiamo. La connessione è statica e viene chiamata una volta. Se l'interno è pieno, si gira da solo. Quindi la connessione viene effettuata una volta. –

+0

Avere un 'DbContext' statico è considerato una cattiva pratica. Può portare a overhead di memoria, problemi con MultiThreading ('DbContext' non è threadsafe) e molto altro. Alaways ne usa uno per qualunque cosa tu definisca * Unità di lavoro * e sii consapevole di quale 'Entità' dipende da quale' DbContext'. Se un 'DbContext' è Smaltato, puoi collegare l'Entità ad un altro Contesto o lavorare con un * Entità Disconnesso * dove tutti i Dati necessari sono già memorizzati nella cache * (Caricamento Eager) *. Un sacco di informazioni per questo argomento possono essere trovate nel web. – LuckyLikey

2

del modello (GetById method) provare a mettere qualcosa di simile:

var billable = _db.Billable.AsNoTracking().SingleOrDefault(i => i.BillableId == id);

Usa AsNoTracking() in modo che restituisca una nuova query in cui i soggetti si non essere memorizzato nella cache nel System.Data.Entity.DbContext

+0

Questo è il migliore! –

+0

@TelsonAlva Grazie! –

Problemi correlati